Import Cobalt 21.master.0.289410
diff --git a/src/build/json_schema_bundle_compile.gypi b/src/build/json_schema_bundle_compile.gypi
deleted file mode 100644
index ecefe41..0000000
--- a/src/build/json_schema_bundle_compile.gypi
+++ /dev/null
@@ -1,62 +0,0 @@
-# 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.
-
-{
- 'variables': {
- # When including this gypi, the following variables must be set:
- # idl_schema_files: an array of idl files that comprise the api model.
- # cc_dir: path to generated files
- # root_namespace: the C++ namespace that all generated files go under
- # Functions and namespaces can be excluded by setting "nocompile" to true.
- 'api_gen_dir': '<(DEPTH)/tools/json_schema_compiler',
- 'api_gen': '<(api_gen_dir)/compiler.py',
- },
- 'actions': [
- {
- 'action_name': 'genapi_bundle',
- 'inputs': [
- '<(api_gen_dir)/cc_generator.py',
- '<(api_gen_dir)/code.py',
- '<(api_gen_dir)/compiler.py',
- '<(api_gen_dir)/cpp_type_generator.py',
- '<(api_gen_dir)/cpp_util.py',
- '<(api_gen_dir)/h_generator.py',
- '<(api_gen_dir)/idl_schema.py',
- '<(api_gen_dir)/json_schema.py',
- '<(api_gen_dir)/model.py',
- '<(api_gen_dir)/schema_bundle_generator.py',
- '<(api_gen_dir)/util_cc_helper.py',
- '<@(idl_schema_files)',
- ],
- 'outputs': [
- '<(SHARED_INTERMEDIATE_DIR)/<(cc_dir)/generated_api.h',
- '<(SHARED_INTERMEDIATE_DIR)/<(cc_dir)/generated_schemas.h',
- '<(SHARED_INTERMEDIATE_DIR)/<(cc_dir)/generated_schemas.cc',
- ],
- 'action': [
- 'python',
- '<(api_gen)',
- '--root=<(DEPTH)',
- '--destdir=<(SHARED_INTERMEDIATE_DIR)',
- '--namespace=<(root_namespace)',
- '--bundle',
- '<@(idl_schema_files)',
- ],
- 'message': 'Generating C++ API bundle code',
- 'process_outputs_as_sources': 1,
- }
- ],
- 'include_dirs': [
- '<(SHARED_INTERMEDIATE_DIR)',
- '<(DEPTH)',
- ],
- 'direct_dependent_settings': {
- 'include_dirs': [
- '<(SHARED_INTERMEDIATE_DIR)',
- ]
- },
- # This target exports a hard dependency because it generates header
- # files.
- 'hard_dependency': 1,
-}
diff --git a/src/build/json_schema_compile.gypi b/src/build/json_schema_compile.gypi
deleted file mode 100644
index 6c8f69c..0000000
--- a/src/build/json_schema_compile.gypi
+++ /dev/null
@@ -1,110 +0,0 @@
-# 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.
-
-{
- 'variables': {
- # When including this gypi, the following variables must be set:
- # json_schema_files: a list of json files that comprise the api model.
- # idl_schema_files: a list of IDL files that comprise the api model.
- # cc_dir: path to generated files
- # root_namespace: the C++ namespace that all generated files go under
- # Functions and namespaces can be excluded by setting "nocompile" to true.
- 'api_gen_dir': '<(DEPTH)/tools/json_schema_compiler',
- 'api_gen': '<(api_gen_dir)/compiler.py',
- },
- 'rules': [
- {
- 'rule_name': 'genapi',
- 'extension': 'json',
- 'inputs': [
- '<(api_gen_dir)/any.cc',
- '<(api_gen_dir)/any.h',
- '<(api_gen_dir)/any_helper.py',
- '<(api_gen_dir)/cc_generator.py',
- '<(api_gen_dir)/code.py',
- '<(api_gen_dir)/compiler.py',
- '<(api_gen_dir)/cpp_type_generator.py',
- '<(api_gen_dir)/cpp_util.py',
- '<(api_gen_dir)/h_generator.py',
- '<(api_gen_dir)/json_schema.py',
- '<(api_gen_dir)/model.py',
- '<(api_gen_dir)/util.cc',
- '<(api_gen_dir)/util.h',
- '<(api_gen_dir)/util_cc_helper.py',
- # TODO(calamity): uncomment this when gyp on windows behaves like other
- # platforms. List expansions of filepaths in inputs expand to different
- # things.
- # '<@(json_schema_files)',
- ],
- 'outputs': [
- '<(SHARED_INTERMEDIATE_DIR)/<(cc_dir)/<(RULE_INPUT_ROOT).cc',
- '<(SHARED_INTERMEDIATE_DIR)/<(cc_dir)/<(RULE_INPUT_ROOT).h',
- ],
- 'action': [
- 'python',
- '<(api_gen)',
- '<(RULE_INPUT_PATH)',
- '--root=<(DEPTH)',
- '--destdir=<(SHARED_INTERMEDIATE_DIR)',
- '--namespace=<(root_namespace)',
- ],
- 'message': 'Generating C++ code from <(RULE_INPUT_PATH) json files',
- 'process_outputs_as_sources': 1,
- },
- {
- 'rule_name': 'genapi_idl',
- 'msvs_external_rule': 1,
- 'extension': 'idl',
- 'inputs': [
- '<(api_gen_dir)/any.cc',
- '<(api_gen_dir)/any.h',
- '<(api_gen_dir)/any_helper.py',
- '<(api_gen_dir)/cc_generator.py',
- '<(api_gen_dir)/code.py',
- '<(api_gen_dir)/compiler.py',
- '<(api_gen_dir)/cpp_type_generator.py',
- '<(api_gen_dir)/cpp_util.py',
- '<(api_gen_dir)/h_generator.py',
- '<(api_gen_dir)/idl_schema.py',
- '<(api_gen_dir)/model.py',
- '<(api_gen_dir)/util.cc',
- '<(api_gen_dir)/util.h',
- '<(api_gen_dir)/util_cc_helper.py',
- # TODO(calamity): uncomment this when gyp on windows behaves like other
- # platforms. List expansions of filepaths in inputs expand to different
- # things.
- # '<@(idl_schema_files)',
- ],
- 'outputs': [
- '<(SHARED_INTERMEDIATE_DIR)/<(cc_dir)/<(RULE_INPUT_ROOT).cc',
- '<(SHARED_INTERMEDIATE_DIR)/<(cc_dir)/<(RULE_INPUT_ROOT).h',
- ],
- 'action': [
- 'python',
- '<(api_gen)',
- '<(RULE_INPUT_PATH)',
- '--root=<(DEPTH)',
- '--destdir=<(SHARED_INTERMEDIATE_DIR)',
- '--namespace=<(root_namespace)',
- ],
- 'message': 'Generating C++ code from <(RULE_INPUT_PATH) IDL files',
- 'process_outputs_as_sources': 1,
- },
- ],
- 'include_dirs': [
- '<(SHARED_INTERMEDIATE_DIR)',
- '<(DEPTH)',
- ],
- 'dependencies':[
- '<(DEPTH)/tools/json_schema_compiler/api_gen_util.gyp:api_gen_util',
- ],
- 'direct_dependent_settings': {
- 'include_dirs': [
- '<(SHARED_INTERMEDIATE_DIR)',
- ]
- },
- # This target exports a hard dependency because it generates header
- # files.
- 'hard_dependency': 1,
-}
diff --git a/src/build/json_to_struct.gypi b/src/build/json_to_struct.gypi
deleted file mode 100644
index 130f6d1..0000000
--- a/src/build/json_to_struct.gypi
+++ /dev/null
@@ -1,49 +0,0 @@
-# Copyright 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.
-
-{
- 'variables': {
- # When including this gypi, the following variables must be set:
- # schema_file: a json file that comprise the structure model.
- # namespace: the C++ namespace that all generated files go under
- # cc_dir: path to generated files
- # Functions and namespaces can be excluded by setting "nocompile" to true.
- 'struct_gen_dir': '<(DEPTH)/tools/json_to_struct',
- 'struct_gen': '<(struct_gen_dir)/json_to_struct.py',
- },
- 'rules': [
- {
- 'rule_name': 'genstaticinit',
- 'extension': 'json',
- 'inputs': [
- '<(struct_gen_dir)/element_generator.py',
- '<(struct_gen_dir)/json_to_struct.py',
- '<(struct_gen_dir)/struct_generator.py',
- '<(schema_file)',
- ],
- 'outputs': [
- '<(SHARED_INTERMEDIATE_DIR)/<(cc_dir)/<(RULE_INPUT_ROOT).cc',
- '<(SHARED_INTERMEDIATE_DIR)/<(cc_dir)/<(RULE_INPUT_ROOT).h',
- ],
- 'action': [
- 'python',
- '<(struct_gen)',
- '<(RULE_INPUT_PATH)',
- '--destbase=<(SHARED_INTERMEDIATE_DIR)',
- '--destdir=<(cc_dir)',
- '--namespace=<(namespace)',
- '--schema=<(schema_file)',
- ],
- 'message': 'Generating C++ static initializers from <(RULE_INPUT_PATH)',
- 'process_outputs_as_sources': 1,
- },
- ],
- 'include_dirs': [
- '<(SHARED_INTERMEDIATE_DIR)',
- '<(DEPTH)',
- ],
- # This target exports a hard dependency because it generates header
- # files.
- 'hard_dependency': 1,
-}
diff --git a/src/build/shim_headers.gypi b/src/build/shim_headers.gypi
deleted file mode 100644
index cf0914d..0000000
--- a/src/build/shim_headers.gypi
+++ /dev/null
@@ -1,45 +0,0 @@
-# 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.
-
-# This file is meant to be included into a target to handle shim headers
-# in a consistent manner. To use this the following variables need to be
-# defined:
-# headers_root_path: string: path to directory containing headers
-# header_filenames: list: list of header file names
-
-{
- 'variables': {
- 'shim_headers_path': '<(INTERMEDIATE_DIR)/shim_headers',
- },
- 'direct_dependent_settings': {
- 'include_dirs+': [
- '<(shim_headers_path)',
- ],
- },
- 'actions': [
- {
- 'variables': {
- 'generator_path': '<(DEPTH)/tools/generate_shim_headers/generate_shim_headers.py',
- 'generator_args': [
- '--headers-root', '<(headers_root_path)',
- '--output-directory', '<(shim_headers_path)',
- '<@(header_filenames)',
- ],
- },
- 'action_name': 'generate_<(_target_name)_shim_headers',
- 'inputs': [
- '<(generator_path)',
- ],
- 'outputs': [
- '<!@pymod_do_main(generate_shim_headers <@(generator_args) --outputs)',
- ],
- 'action': ['python',
- '<(generator_path)',
- '<@(generator_args)',
- '--generate',
- ],
- 'message': 'Generating <(_target_name) shim headers.',
- },
- ],
-}
diff --git a/src/cobalt/CHANGELOG.md b/src/cobalt/CHANGELOG.md
index f2872b4..644ecae 100644
--- a/src/cobalt/CHANGELOG.md
+++ b/src/cobalt/CHANGELOG.md
@@ -119,6 +119,12 @@
the comment of `SbMediaCanPlayMimeAndKeySystem()` in `media.h` for more
details.
+ - **Added support for controlling shutdown behavior of graphics system.**
+
+ Cobalt normally clears the framebuffer to opaque black on suspend or exit.
+ This behavior can now be overridden by implementing the cobalt extension
+ function `CobaltExtensionGraphicsApi::ShouldClearFrameOnShutdown`.
+
## Version 20
- **Support for QUIC and SPDY is now enabled.**
diff --git a/src/cobalt/audio/audio_test.gyp b/src/cobalt/audio/audio_test.gyp
index c4e3979..97bd3f9 100644
--- a/src/cobalt/audio/audio_test.gyp
+++ b/src/cobalt/audio/audio_test.gyp
@@ -24,6 +24,7 @@
'audio_node_input_output_test.cc',
],
'dependencies': [
+ '<@(cobalt_platform_dependencies)',
'<(DEPTH)/cobalt/dom/dom.gyp:dom',
'<(DEPTH)/cobalt/media/media.gyp:media',
'<(DEPTH)/testing/gmock.gyp:gmock',
diff --git a/src/cobalt/bindings/run_cobalt_bindings_tests.py b/src/cobalt/bindings/run_cobalt_bindings_tests.py
index eb0fe24..33f7494 100755
--- a/src/cobalt/bindings/run_cobalt_bindings_tests.py
+++ b/src/cobalt/bindings/run_cobalt_bindings_tests.py
@@ -25,12 +25,12 @@
import argparse
import os
import sys
-from webkitpy.bindings.bindings_tests import run_bindings_tests
-
import _env # pylint: disable=unused-import
+
from cobalt.bindings.idl_compiler_cobalt import IdlCompilerCobalt
from cobalt.bindings.mozjs45.code_generator_mozjs45 import CodeGeneratorMozjs45
from cobalt.bindings.v8c.code_generator_v8c import CodeGeneratorV8c
+from webkitpy.bindings.bindings_tests import run_bindings_tests
def main(argv):
diff --git a/src/cobalt/bindings/testing/date_bindings_test.cc b/src/cobalt/bindings/testing/date_bindings_test.cc
index 602f2ee..bb58362 100644
--- a/src/cobalt/bindings/testing/date_bindings_test.cc
+++ b/src/cobalt/bindings/testing/date_bindings_test.cc
@@ -14,8 +14,11 @@
#include "base/logging.h"
+#include "base/time/time.h"
#include "cobalt/bindings/testing/bindings_test_base.h"
#include "cobalt/bindings/testing/interface_with_date.h"
+#include "starboard/client_porting/eztime/eztime.h"
+#include "starboard/time_zone.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -79,6 +82,45 @@
EXPECT_LT(std::abs(posix_now_ms - js_now_ms), 1000);
}
+TEST_F(DateBindingsTest, StarboardTimeZone) {
+ const char* month_table[] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun",
+ "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
+ std::string result;
+
+ EvaluateScript("new Date().toString();", &result);
+ base::Time now = base::Time::Now();
+
+ SB_LOG(INFO) << "JavaScript Date now is : " << result;
+ SB_LOG(INFO) << "and base::Time is: " << now;
+
+ base::Time::Exploded exploded;
+ now.LocalExplode(&exploded);
+ EXPECT_NE(result.find(std::to_string(exploded.year)), std::string::npos);
+ EXPECT_NE(result.find(month_table[exploded.month - 1]), std::string::npos);
+ EXPECT_NE(result.find(std::to_string(exploded.day_of_month)),
+ std::string::npos);
+ EXPECT_NE(result.find(std::to_string(exploded.hour)), std::string::npos);
+ EXPECT_NE(result.find(std::to_string(exploded.minute)), std::string::npos);
+ EXPECT_NE(result.find(std::to_string(exploded.second)), std::string::npos);
+}
+
+TEST_F(DateBindingsTest, TimezoneOffset) {
+ EzTimeExploded ez_exploded;
+
+ auto eztt = EzTimeTFromSbTime(SbTimeGetNow());
+ EzTimeTExplodeLocal(&eztt, &ez_exploded);
+ // ez_exploded is already local time, use UTC method to convert to
+ // EzTimeT.
+ EzTimeT local_time_minutes = EzTimeTImplodeUTC(&ez_exploded) / 60;
+ EzTimeT utc_minutes = EzTimeTFromSbTime(SbTimeGetNow()) / 60;
+ EzTimeT timezone_offset = utc_minutes - local_time_minutes;
+
+ std::string result;
+ EvaluateScript("new Date().getTimezoneOffset();", &result);
+
+ EXPECT_EQ(result, std::to_string(utc_minutes - local_time_minutes));
+}
+
} // namespace
} // namespace testing
} // namespace bindings
diff --git a/src/cobalt/black_box_tests/black_box_tests.py b/src/cobalt/black_box_tests/black_box_tests.py
index 60f5596..271b2cc 100644
--- a/src/cobalt/black_box_tests/black_box_tests.py
+++ b/src/cobalt/black_box_tests/black_box_tests.py
@@ -35,6 +35,7 @@
_DISABLED_BLACKBOXTEST_CONFIGS = [
'android-arm/devel',
'android-arm64/devel',
+ 'android-x86/devel',
'raspi-0/devel',
]
diff --git a/src/cobalt/browser/browser_module.cc b/src/cobalt/browser/browser_module.cc
index ace1e98..d709ff7 100644
--- a/src/cobalt/browser/browser_module.cc
+++ b/src/cobalt/browser/browser_module.cc
@@ -637,7 +637,7 @@
#endif // ENABLE_DEBUGGER
// Pass down this callback from to Web module.
- options_.web_module_options.maybe_freeze_callback =
+ options.maybe_freeze_callback =
base::Bind(&BrowserModule::OnMaybeFreeze, base::Unretained(this));
web_module_.reset(new WebModule(
@@ -1830,7 +1830,8 @@
#if defined(ENABLE_DEBUGGER)
debug_console_ready_to_freeze &&
#endif // defined(ENABLE_DEBUGGER)
- web_module_ready_to_freeze) {
+ web_module_ready_to_freeze &&
+ application_state_ == base::kApplicationStateConcealed) {
#if SB_API_VERSION >= SB_ADD_CONCEALED_STATE_SUPPORT_VERSION || \
SB_HAS(CONCEALED_STATE)
SbSystemRequestFreeze();
diff --git a/src/cobalt/browser/memory_settings/memory_settings.h b/src/cobalt/browser/memory_settings/memory_settings.h
index 3aee9b5..afaeef6 100644
--- a/src/cobalt/browser/memory_settings/memory_settings.h
+++ b/src/cobalt/browser/memory_settings/memory_settings.h
@@ -107,7 +107,8 @@
private:
// Default constructor for MemorySetting is forbidden. Do not use it.
MemorySetting();
- SB_DISALLOW_COPY_AND_ASSIGN(MemorySetting);
+ MemorySetting(const MemorySetting&) = delete;
+ void operator=(const MemorySetting&) = delete;
};
// A memory setting for integer values.
@@ -135,7 +136,8 @@
private:
int64_t value_;
- SB_DISALLOW_COPY_AND_ASSIGN(IntSetting);
+ IntSetting(const IntSetting&) = delete;
+ void operator=(const IntSetting&) = delete;
};
// A memory setting for dimensions type values like "2048x4096x2" where
@@ -166,7 +168,8 @@
private:
TextureDimensions value_;
- SB_DISALLOW_COPY_AND_ASSIGN(DimensionSetting);
+ DimensionSetting(const DimensionSetting&) = delete;
+ void operator=(const DimensionSetting&) = delete;
};
class SkiaGlyphAtlasTextureSetting : public DimensionSetting {
diff --git a/src/cobalt/browser/web_module.cc b/src/cobalt/browser/web_module.cc
index 9748ca1..10124f4 100644
--- a/src/cobalt/browser/web_module.cc
+++ b/src/cobalt/browser/web_module.cc
@@ -52,6 +52,7 @@
#include "cobalt/dom/keyboard_event_init.h"
#include "cobalt/dom/local_storage_database.h"
#include "cobalt/dom/mutation_observer_task_manager.h"
+#include "cobalt/dom/navigator.h"
#include "cobalt/dom/pointer_event.h"
#include "cobalt/dom/storage.h"
#include "cobalt/dom/ui_event.h"
@@ -240,7 +241,13 @@
void CancelSynchronousLoads();
void IsReadyToFreeze(volatile bool* is_ready_to_freeze) {
- *is_ready_to_freeze = !media_session_client_->is_active();
+ if (window_->media_session()->media_session_client() == NULL) {
+ *is_ready_to_freeze = true;
+ return;
+ }
+
+ *is_ready_to_freeze =
+ !window_->media_session()->media_session_client()->is_active();
}
private:
@@ -432,8 +439,6 @@
// DocumentObserver that observes the loading document.
std::unique_ptr<DocumentLoadedObserver> document_load_observer_;
- std::unique_ptr<media_session::MediaSessionClient> media_session_client_;
-
std::unique_ptr<layout::TopmostEventTarget> topmost_event_target_;
base::Closure on_before_unload_fired_but_not_handled_;
@@ -592,11 +597,6 @@
&mutation_observer_task_manager_, data.options.dom_settings_options));
DCHECK(environment_settings_);
- media_session_client_ = media_session::MediaSessionClient::Create();
- media_session_client_->SetMediaPlayerFactory(data.web_media_player_factory);
- media_session_client_->SetMaybeFreezeCallback(
- data.options.maybe_freeze_callback);
-
system_caption_settings_ = new cobalt::dom::captions::SystemCaptionSettings(
environment_settings_.get());
@@ -653,7 +653,6 @@
base::Unretained(this)),
data.window_close_callback, data.window_minimize_callback,
data.options.on_screen_keyboard_bridge, data.options.camera_3d,
- media_session_client_->GetMediaSession(),
base::Bind(&WebModule::Impl::OnStartDispatchEvent,
base::Unretained(this)),
base::Bind(&WebModule::Impl::OnStopDispatchEvent, base::Unretained(this)),
@@ -686,6 +685,11 @@
error_callback_ = data.error_callback;
DCHECK(!error_callback_.is_null());
+ window_->navigator()->set_maybefreeze_callback(
+ data.options.maybe_freeze_callback);
+ window_->navigator()->set_media_player_factory(
+ data.web_media_player_factory);
+
bool is_concealed =
(data.initial_application_state == base::kApplicationStateConcealed);
layout_manager_.reset(new layout::LayoutManager(
@@ -749,7 +753,6 @@
script::GlobalEnvironment::ReportErrorCallback());
window_->DispatchEvent(new dom::Event(base::Tokens::unload()));
document_load_observer_.reset();
- media_session_client_.reset();
#if defined(ENABLE_DEBUGGER)
debug_module_.reset();
@@ -1069,7 +1072,6 @@
void WebModule::Impl::SetWebMediaPlayerFactory(
media::WebMediaPlayerFactory* web_media_player_factory) {
window_->set_web_media_player_factory(web_media_player_factory);
- media_session_client_->SetMediaPlayerFactory(web_media_player_factory);
}
void WebModule::Impl::SetApplicationState(base::ApplicationState state) {
diff --git a/src/cobalt/build/build.id b/src/cobalt/build/build.id
index 396f316..3fcc752 100644
--- a/src/cobalt/build/build.id
+++ b/src/cobalt/build/build.id
@@ -1 +1 @@
-286167
\ No newline at end of file
+289410
\ No newline at end of file
diff --git a/src/cobalt/build/cobalt_configuration.gypi b/src/cobalt/build/cobalt_configuration.gypi
index 7f4f3c6..7880f93 100644
--- a/src/cobalt/build/cobalt_configuration.gypi
+++ b/src/cobalt/build/cobalt_configuration.gypi
@@ -523,10 +523,6 @@
# further reduced on systems with extremely low memory.
'cobalt_media_source_garbage_collection_duration_threshold_in_seconds%': -1,
- 'compiler_flags_host': [
- '-D__LB_HOST__', # TODO: Is this still needed?
- ],
-
'defines_debug': [
'ALLOCATOR_STATS_TRACKING',
'COBALT_BOX_DUMP_ENABLED',
diff --git a/src/cobalt/build/cobalt_configuration.py b/src/cobalt/build/cobalt_configuration.py
index 2cd04f6..b178ed5 100644
--- a/src/cobalt/build/cobalt_configuration.py
+++ b/src/cobalt/build/cobalt_configuration.py
@@ -38,8 +38,17 @@
application_directory)
def GetVariables(self, config_name):
+
+ # Use env var to optimize build speed on CI
+ try:
+ # Force to int, so it's easy to pass in an override.
+ use_fastbuild = int(os.environ.get('IS_CI', 0))
+ except (ValueError, TypeError):
+ use_fastbuild = 0
+
variables = {
- 'cobalt_fastbuild': os.environ.get('LB_FASTBUILD', 0),
+ # This is used to omit large debuginfo in files on CI environment
+ 'cobalt_fastbuild': use_fastbuild,
# This is here rather than cobalt_configuration.gypi so that it's
# available for browser_bindings_gen.gyp.
@@ -119,7 +128,7 @@
# Disabled because of: Flaky on buildbot across multiple buildconfigs.
# Non-reproducible with local runs.
('xhr/WebPlatformTest.Run/'
- 'XMLHttpRequest_send_entity_body_get_head_async_htm'),
+ 'XMLHttpRequest_send_entity_body_get_head_async_htm'),
'xhr/WebPlatformTest.Run/XMLHttpRequest_status_error_htm',
'xhr/WebPlatformTest.Run/XMLHttpRequest_response_json_htm',
'xhr/WebPlatformTest.Run/XMLHttpRequest_send_redirect_to_non_cors_htm',
diff --git a/src/cobalt/css_parser/css_parser.gyp b/src/cobalt/css_parser/css_parser.gyp
index d07f4c8..aa4ae4a 100644
--- a/src/cobalt/css_parser/css_parser.gyp
+++ b/src/cobalt/css_parser/css_parser.gyp
@@ -33,6 +33,8 @@
{
'target_name': 'css_grammar',
'type': 'none',
+ # This target generates header files which may be used by other targets.
+ 'hard_dependency': 1,
'sources': [
'grammar.h',
'grammar.y'
diff --git a/src/cobalt/css_parser/grammar.y b/src/cobalt/css_parser/grammar.y
index 920cce8..6909469 100644
--- a/src/cobalt/css_parser/grammar.y
+++ b/src/cobalt/css_parser/grammar.y
@@ -4882,7 +4882,17 @@
| kCobaltUiNavFocusTransformFunctionToken maybe_whitespace ')'
maybe_whitespace {
$<transform_functions>0->emplace_back(
- new cssom::CobaltUiNavFocusTransformFunction);
+ new cssom::CobaltUiNavFocusTransformFunction(1.0f, 1.0f));
+ }
+ | kCobaltUiNavFocusTransformFunctionToken maybe_whitespace number ')'
+ maybe_whitespace {
+ $<transform_functions>0->emplace_back(
+ new cssom::CobaltUiNavFocusTransformFunction($3, $3));
+ }
+ | kCobaltUiNavFocusTransformFunctionToken maybe_whitespace number comma
+ number ')' maybe_whitespace {
+ $<transform_functions>0->emplace_back(
+ new cssom::CobaltUiNavFocusTransformFunction($3, $5));
}
// This Cobalt-specific transform function for hybrid navigation tracks
// the direction in which focus is moving. This can be used to provide
diff --git a/src/cobalt/css_parser/parser_test.cc b/src/cobalt/css_parser/parser_test.cc
index 040c178..d510f2c 100644
--- a/src/cobalt/css_parser/parser_test.cc
+++ b/src/cobalt/css_parser/parser_test.cc
@@ -7223,7 +7223,55 @@
TEST_F(ParserTest, ParsesCobaltUiNavFocusTransform) {
scoped_refptr<cssom::CSSDeclaredStyleData> style =
parser_.ParseStyleDeclarationList(
- "transform: -cobalt-ui-nav-focus-transform();",
+ "transform: -cobalt-ui-nav-focus-transform();", source_location_);
+
+ ASSERT_TRUE(style->IsDeclared(cssom::kTransformProperty));
+ scoped_refptr<cssom::TransformFunctionListValue> transform_list =
+ dynamic_cast<cssom::TransformFunctionListValue*>(
+ style->GetPropertyValue(cssom::kTransformProperty).get());
+ ASSERT_TRUE(transform_list);
+ EXPECT_TRUE(transform_list->value().HasTrait(kTraitIsDynamic));
+ EXPECT_FALSE(transform_list->value().HasTrait(kTraitUsesRelativeUnits));
+ EXPECT_TRUE(transform_list->value().HasTrait(kTraitUsesUiNavFocus));
+ ASSERT_EQ(1, transform_list->value().size());
+
+ const cssom::CobaltUiNavFocusTransformFunction* focus_function =
+ dynamic_cast<const cssom::CobaltUiNavFocusTransformFunction*>(
+ transform_list->value()[0].get());
+ ASSERT_TRUE(focus_function);
+
+ EXPECT_FLOAT_EQ(1.0f, focus_function->x_translation_scale());
+ EXPECT_FLOAT_EQ(1.0f, focus_function->y_translation_scale());
+}
+
+TEST_F(ParserTest, ParsesCobaltUiNavFocusTransformOneArgument) {
+ scoped_refptr<cssom::CSSDeclaredStyleData> style =
+ parser_.ParseStyleDeclarationList(
+ "transform: -cobalt-ui-nav-focus-transform(2);", source_location_);
+
+ ASSERT_TRUE(style->IsDeclared(cssom::kTransformProperty));
+ scoped_refptr<cssom::TransformFunctionListValue> transform_list =
+ dynamic_cast<cssom::TransformFunctionListValue*>(
+ style->GetPropertyValue(cssom::kTransformProperty).get());
+ ASSERT_TRUE(transform_list);
+ EXPECT_TRUE(transform_list->value().HasTrait(kTraitIsDynamic));
+ EXPECT_FALSE(transform_list->value().HasTrait(kTraitUsesRelativeUnits));
+ EXPECT_TRUE(transform_list->value().HasTrait(kTraitUsesUiNavFocus));
+ ASSERT_EQ(1, transform_list->value().size());
+
+ const cssom::CobaltUiNavFocusTransformFunction* focus_function =
+ dynamic_cast<const cssom::CobaltUiNavFocusTransformFunction*>(
+ transform_list->value()[0].get());
+ ASSERT_TRUE(focus_function);
+
+ EXPECT_FLOAT_EQ(2.0f, focus_function->x_translation_scale());
+ EXPECT_FLOAT_EQ(2.0f, focus_function->y_translation_scale());
+}
+
+TEST_F(ParserTest, ParsesCobaltUiNavFocusTransformTwoArguments) {
+ scoped_refptr<cssom::CSSDeclaredStyleData> style =
+ parser_.ParseStyleDeclarationList(
+ "transform: -cobalt-ui-nav-focus-transform(0.5, 2);",
source_location_);
ASSERT_TRUE(style->IsDeclared(cssom::kTransformProperty));
@@ -7240,13 +7288,15 @@
dynamic_cast<const cssom::CobaltUiNavFocusTransformFunction*>(
transform_list->value()[0].get());
ASSERT_TRUE(focus_function);
+
+ EXPECT_FLOAT_EQ(0.5f, focus_function->x_translation_scale());
+ EXPECT_FLOAT_EQ(2.0f, focus_function->y_translation_scale());
}
TEST_F(ParserTest, ParsesCobaltUiNavSpotlightTransform) {
scoped_refptr<cssom::CSSDeclaredStyleData> style =
parser_.ParseStyleDeclarationList(
- "transform: -cobalt-ui-nav-spotlight-transform();",
- source_location_);
+ "transform: -cobalt-ui-nav-spotlight-transform();", source_location_);
ASSERT_TRUE(style->IsDeclared(cssom::kTransformProperty));
scoped_refptr<cssom::TransformFunctionListValue> transform_list =
@@ -8532,8 +8582,9 @@
TEST_F(ParserTest, ParsesAnimatablePropertyNameListWithSingleValue) {
scoped_refptr<cssom::PropertyKeyListValue> property_name_list =
dynamic_cast<cssom::PropertyKeyListValue*>(
- parser_.ParsePropertyValue("transition-property", "color",
- source_location_)
+ parser_
+ .ParsePropertyValue("transition-property", "color",
+ source_location_)
.get());
ASSERT_TRUE(property_name_list);
@@ -8544,9 +8595,10 @@
TEST_F(ParserTest, ParsesAnimatablePropertyNameListWithMultipleValues) {
scoped_refptr<cssom::PropertyKeyListValue> property_name_list =
dynamic_cast<cssom::PropertyKeyListValue*>(
- parser_.ParsePropertyValue("transition-property",
- "color, transform , background-color",
- source_location_)
+ parser_
+ .ParsePropertyValue("transition-property",
+ "color, transform , background-color",
+ source_location_)
.get());
ASSERT_TRUE(property_name_list);
@@ -8559,8 +8611,9 @@
TEST_F(ParserTest, ParsesTransitionPropertyWithAllValue) {
scoped_refptr<cssom::PropertyKeyListValue> property_name_list =
dynamic_cast<cssom::PropertyKeyListValue*>(
- parser_.ParsePropertyValue("transition-property", "all",
- source_location_)
+ parser_
+ .ParsePropertyValue("transition-property", "all",
+ source_location_)
.get());
ASSERT_TRUE(property_name_list.get());
@@ -8593,8 +8646,9 @@
TEST_F(ParserTest, ParsesTimeListWithSingleValue) {
scoped_refptr<cssom::TimeListValue> time_list_value =
dynamic_cast<cssom::TimeListValue*>(
- parser_.ParsePropertyValue("transition-duration", "1s",
- source_location_).get());
+ parser_
+ .ParsePropertyValue("transition-duration", "1s", source_location_)
+ .get());
ASSERT_TRUE(time_list_value.get());
ASSERT_EQ(1, time_list_value->value().size());
@@ -8604,9 +8658,10 @@
TEST_F(ParserTest, ParsesTimeListWithMultipleValues) {
scoped_refptr<cssom::TimeListValue> time_list_value =
dynamic_cast<cssom::TimeListValue*>(
- parser_.ParsePropertyValue("transition-duration",
- "2s, 1ms, 0, 2ms, 3s, 3ms",
- source_location_).get());
+ parser_
+ .ParsePropertyValue("transition-duration",
+ "2s, 1ms, 0, 2ms, 3s, 3ms", source_location_)
+ .get());
ASSERT_TRUE(time_list_value.get());
ASSERT_EQ(6, time_list_value->value().size());
@@ -8621,8 +8676,10 @@
TEST_F(ParserTest, ParsesNegativeTimeList) {
scoped_refptr<cssom::TimeListValue> time_list_value =
dynamic_cast<cssom::TimeListValue*>(
- parser_.ParsePropertyValue("transition-duration", "-4s",
- source_location_).get());
+ parser_
+ .ParsePropertyValue("transition-duration", "-4s",
+ source_location_)
+ .get());
ASSERT_TRUE(time_list_value.get());
ASSERT_EQ(1, time_list_value->value().size());
@@ -8780,52 +8837,52 @@
}
TEST_F(ParserTest, AboveRangeCubicBezierP1XParameterProduceError) {
- EXPECT_CALL(parser_observer_,
- OnError(
- "[object ParserTest]:1:1: error: cubic-bezier control point "
- "x values must be in the range [0, 1]."));
+ EXPECT_CALL(
+ parser_observer_,
+ OnError("[object ParserTest]:1:1: error: cubic-bezier control point "
+ "x values must be in the range [0, 1]."));
scoped_refptr<cssom::PropertyValue> error_value = parser_.ParsePropertyValue(
"transition-timing-function", "cubic-bezier(2, 0, 0.5, 0)",
source_location_);
// Test that the ease function was returned in place of the error function.
EXPECT_TRUE(error_value->Equals(*CreateSingleTimingFunctionValue(
- cssom::TimingFunction::GetEase().get())));
+ cssom::TimingFunction::GetEase().get())));
}
TEST_F(ParserTest, BelowRangeCubicBezierP1XParameterProduceError) {
- EXPECT_CALL(parser_observer_,
- OnError(
- "[object ParserTest]:1:1: error: cubic-bezier control point "
- "x values must be in the range [0, 1]."));
+ EXPECT_CALL(
+ parser_observer_,
+ OnError("[object ParserTest]:1:1: error: cubic-bezier control point "
+ "x values must be in the range [0, 1]."));
scoped_refptr<cssom::PropertyValue> error_value = parser_.ParsePropertyValue(
"transition-timing-function", "cubic-bezier(-1, 0, 0.5, 0)",
source_location_);
// Test that the ease function was returned in place of the error function.
EXPECT_TRUE(error_value->Equals(*CreateSingleTimingFunctionValue(
- cssom::TimingFunction::GetEase().get())));
+ cssom::TimingFunction::GetEase().get())));
}
TEST_F(ParserTest, AboveRangeCubicBezierP2XParameterProduceError) {
- EXPECT_CALL(parser_observer_,
- OnError(
- "[object ParserTest]:1:1: error: cubic-bezier control point "
- "x values must be in the range [0, 1]."));
+ EXPECT_CALL(
+ parser_observer_,
+ OnError("[object ParserTest]:1:1: error: cubic-bezier control point "
+ "x values must be in the range [0, 1]."));
scoped_refptr<cssom::PropertyValue> error_value = parser_.ParsePropertyValue(
"transition-timing-function", "cubic-bezier(0.5, 0, 2, 0)",
source_location_);
// Test that the ease function was returned in place of the error function.
EXPECT_TRUE(error_value->Equals(*CreateSingleTimingFunctionValue(
- cssom::TimingFunction::GetEase().get())));
+ cssom::TimingFunction::GetEase().get())));
}
TEST_F(ParserTest, BelowRangeCubicBezierP2XParameterProduceError) {
- EXPECT_CALL(parser_observer_,
- OnError(
- "[object ParserTest]:1:1: error: cubic-bezier control point "
- "x values must be in the range [0, 1]."));
+ EXPECT_CALL(
+ parser_observer_,
+ OnError("[object ParserTest]:1:1: error: cubic-bezier control point "
+ "x values must be in the range [0, 1]."));
scoped_refptr<cssom::PropertyValue> error_value = parser_.ParsePropertyValue(
"transition-timing-function", "cubic-bezier(0.5, 0, -1, 0)",
source_location_);
// Test that the ease function was returned in place of the error function.
EXPECT_TRUE(error_value->Equals(*CreateSingleTimingFunctionValue(
- cssom::TimingFunction::GetEase().get())));
+ cssom::TimingFunction::GetEase().get())));
}
TEST_F(ParserTest, ParsesTransitionShorthandOfMultipleItemsWithNoDefaults) {
@@ -9156,9 +9213,9 @@
}
TEST_F(ParserTest, ParsesTransitionShorthandWithErrorBeforeSemicolon) {
- EXPECT_CALL(parser_observer_, OnError(
- "[object ParserTest]:1:16: error: "
- "unsupported property value for animation"))
+ EXPECT_CALL(parser_observer_,
+ OnError("[object ParserTest]:1:16: error: "
+ "unsupported property value for animation"))
.Times(AtLeast(1));
scoped_refptr<cssom::CSSDeclaredStyleData> style =
@@ -9187,9 +9244,9 @@
}
TEST_F(ParserTest, ParsesTransitionShorthandWithErrorBeforeSpace) {
- EXPECT_CALL(parser_observer_, OnError(
- "[object ParserTest]:1:16: error: "
- "unsupported property value for animation"))
+ EXPECT_CALL(parser_observer_,
+ OnError("[object ParserTest]:1:16: error: "
+ "unsupported property value for animation"))
.Times(AtLeast(1));
scoped_refptr<cssom::CSSDeclaredStyleData> style =
@@ -9215,9 +9272,9 @@
TEST_F(ParserTest,
ParsesTransitionShorthandIgnoringErrorButProceedingWithNonError) {
- EXPECT_CALL(parser_observer_, OnError(
- "[object ParserTest]:1:16: error: "
- "unsupported property value for animation"))
+ EXPECT_CALL(parser_observer_,
+ OnError("[object ParserTest]:1:16: error: "
+ "unsupported property value for animation"))
.Times(AtLeast(1));
scoped_refptr<cssom::CSSDeclaredStyleData> style =
@@ -9737,8 +9794,9 @@
TEST_F(ParserTest, ParsesValidMediaQuery) {
scoped_refptr<cssom::MediaQuery> media_query =
- parser_.ParseMediaQuery("(max-width: 1024px) and (max-height: 512px)",
- source_location_)
+ parser_
+ .ParseMediaQuery("(max-width: 1024px) and (max-height: 512px)",
+ source_location_)
.get();
ASSERT_TRUE(media_query.get());
// TODO: Update when media query serialization is implemented.
@@ -9754,8 +9812,9 @@
TEST_F(ParserTest, ParsesValidMediaList) {
scoped_refptr<cssom::MediaList> media_list =
- parser_.ParseMediaList("(max-width: 1024px), (max-height: 512px)",
- source_location_)
+ parser_
+ .ParseMediaList("(max-width: 1024px), (max-height: 512px)",
+ source_location_)
.get();
ASSERT_TRUE(media_list.get());
ASSERT_EQ(media_list->length(), 2);
@@ -9766,9 +9825,10 @@
TEST_F(ParserTest, ParsesValidMediaQueryWithIntegers) {
scoped_refptr<cssom::MediaQuery> media_query =
- parser_.ParseMediaQuery(
- "(color: 8) and (grid:0) and (color) and (scan: progressive)",
- source_location_)
+ parser_
+ .ParseMediaQuery(
+ "(color: 8) and (grid:0) and (color) and (scan: progressive)",
+ source_location_)
.get();
ASSERT_TRUE(media_query.get());
diff --git a/src/cobalt/cssom/cobalt_ui_nav_focus_transform_function.cc b/src/cobalt/cssom/cobalt_ui_nav_focus_transform_function.cc
index c250141..b29ec28 100644
--- a/src/cobalt/cssom/cobalt_ui_nav_focus_transform_function.cc
+++ b/src/cobalt/cssom/cobalt_ui_nav_focus_transform_function.cc
@@ -14,6 +14,7 @@
#include "cobalt/cssom/cobalt_ui_nav_focus_transform_function.h"
+#include "base/strings/stringprintf.h"
#include "cobalt/cssom/transform_function_visitor.h"
#include "cobalt/math/matrix_interpolation.h"
@@ -21,8 +22,11 @@
namespace cssom {
CobaltUiNavFocusTransformFunction::CobaltUiNavFocusTransformFunction(
+ float x_translation_scale, float y_translation_scale,
float progress_to_identity)
- : progress_to_identity_(progress_to_identity) {
+ : x_translation_scale_(x_translation_scale),
+ y_translation_scale_(y_translation_scale),
+ progress_to_identity_(progress_to_identity) {
traits_ = kTraitIsDynamic | kTraitUsesUiNavFocus;
}
@@ -32,22 +36,22 @@
}
std::string CobaltUiNavFocusTransformFunction::ToString() const {
- return "-cobalt-ui-nav-focus-transform()";
+ return base::StringPrintf("-cobalt-ui-nav-focus-transform(%.7g, %.7g)",
+ x_translation_scale_, y_translation_scale_);
}
math::Matrix3F CobaltUiNavFocusTransformFunction::ToMatrix(
const math::SizeF& used_size,
const scoped_refptr<ui_navigation::NavItem>& used_ui_nav_focus) const {
ui_navigation::NativeMatrix4 matrix;
- if (used_ui_nav_focus &&
- used_ui_nav_focus->GetFocusTransform(&matrix)) {
+ if (used_ui_nav_focus && used_ui_nav_focus->GetFocusTransform(&matrix)) {
return math::InterpolateMatrices(
math::Matrix3F::FromValues(
- matrix.m[ 0], matrix.m[ 1], matrix.m[ 3],
- matrix.m[ 4], matrix.m[ 5], matrix.m[ 7],
- matrix.m[12], matrix.m[13], matrix.m[15]),
- math::Matrix3F::Identity(),
- progress_to_identity_);
+ // Since the UI is only rendered in 2D, ignore any scaling or
+ // shearing that might be part of a 3D transform.
+ 1.0f, 0.0f, matrix.m[3] * x_translation_scale_, 0.0f, 1.0f,
+ matrix.m[7] * y_translation_scale_, 0.0f, 0.0f, 1.0f),
+ math::Matrix3F::Identity(), progress_to_identity_);
}
return math::Matrix3F::Identity();
}
diff --git a/src/cobalt/cssom/cobalt_ui_nav_focus_transform_function.h b/src/cobalt/cssom/cobalt_ui_nav_focus_transform_function.h
index 210786b..ed31665 100644
--- a/src/cobalt/cssom/cobalt_ui_nav_focus_transform_function.h
+++ b/src/cobalt/cssom/cobalt_ui_nav_focus_transform_function.h
@@ -39,26 +39,33 @@
// resulting in this transform returning the identity matrix. DOM elements
// will only ever use progress_to_identity == 0, but intermediate animation
// frames may use other values.
- explicit CobaltUiNavFocusTransformFunction(
- float progress_to_identity = 0.0f);
+ CobaltUiNavFocusTransformFunction(float x_translation_scale,
+ float y_translation_scale,
+ float progress_to_identity = 0.0f);
void Accept(TransformFunctionVisitor* visitor) const override;
+ float x_translation_scale() const { return x_translation_scale_; }
+ float y_translation_scale() const { return y_translation_scale_; }
float progress_to_identity() const { return progress_to_identity_; }
std::string ToString() const override;
math::Matrix3F ToMatrix(const math::SizeF& used_size,
- const scoped_refptr<ui_navigation::NavItem>& used_ui_nav_focus)
- const override;
+ const scoped_refptr<ui_navigation::NavItem>&
+ used_ui_nav_focus) const override;
bool operator==(const CobaltUiNavFocusTransformFunction& other) const {
- return progress_to_identity_ == other.progress_to_identity_;
+ return x_translation_scale_ == other.x_translation_scale_ &&
+ y_translation_scale_ == other.y_translation_scale_ &&
+ progress_to_identity_ == other.progress_to_identity_;
}
DEFINE_POLYMORPHIC_EQUATABLE_TYPE(CobaltUiNavFocusTransformFunction);
private:
+ const float x_translation_scale_;
+ const float y_translation_scale_;
const float progress_to_identity_;
};
diff --git a/src/cobalt/cssom/interpolate_property_value.cc b/src/cobalt/cssom/interpolate_property_value.cc
index b781e1a..79f0d1f 100644
--- a/src/cobalt/cssom/interpolate_property_value.cc
+++ b/src/cobalt/cssom/interpolate_property_value.cc
@@ -17,6 +17,7 @@
#include <algorithm>
#include <limits>
#include <memory>
+#include <utility>
#include "base/memory/ptr_util.h"
#include "cobalt/base/enable_if.h"
@@ -269,11 +270,23 @@
// identity matrix when transitioning to transform none. Instead, the
// focus transform needs to know how close to the identity transform it
// needs to interpolate its value when evaluated.
- float progress_to_identity_end =
- focus_end ? focus_end->progress_to_identity() : 1.0f;
+ float progress_to_identity_end = 1.0f;
+ // Maintain the translation scale values if interpolating to identity since
+ // the interpolation to identity is also phasing out the translation scales.
+ float x_translation_scale_end = focus_function->x_translation_scale();
+ float y_translation_scale_end = focus_function->y_translation_scale();
+ if (focus_end) {
+ progress_to_identity_end = focus_end->progress_to_identity();
+ x_translation_scale_end = focus_end->x_translation_scale();
+ y_translation_scale_end = focus_end->y_translation_scale();
+ }
animated_.reset(new CobaltUiNavFocusTransformFunction(
- Lerp(focus_function->progress_to_identity(),
- progress_to_identity_end, progress_)));
+ Lerp(focus_function->x_translation_scale(), x_translation_scale_end,
+ progress_),
+ Lerp(focus_function->y_translation_scale(), y_translation_scale_end,
+ progress_),
+ Lerp(focus_function->progress_to_identity(), progress_to_identity_end,
+ progress_)));
}
void AnimateTransformFunction::VisitCobaltUiNavSpotlightTransform(
@@ -289,8 +302,8 @@
float progress_to_identity_end =
spotlight_end ? spotlight_end->progress_to_identity() : 1.0f;
animated_.reset(new CobaltUiNavSpotlightTransformFunction(
- Lerp(spotlight_function->progress_to_identity(),
- progress_to_identity_end, progress_)));
+ Lerp(spotlight_function->progress_to_identity(), progress_to_identity_end,
+ progress_)));
}
// Returns true if two given transform function lists have the same number of
@@ -339,13 +352,11 @@
}
TransformFunctionListValue* start_transform =
- base::polymorphic_downcast<TransformFunctionListValue*>(
- start_value);
+ base::polymorphic_downcast<TransformFunctionListValue*>(start_value);
TransformFunctionListValue* end_transform =
end_value->Equals(*KeywordValue::GetNone())
? NULL
- : base::polymorphic_downcast<TransformFunctionListValue*>(
- end_value);
+ : base::polymorphic_downcast<TransformFunctionListValue*>(end_value);
const TransformFunctionListValue::Builder* start_functions =
&start_transform->value();
@@ -377,8 +388,8 @@
// into a matrix and animate the matrix using the algorithm described here:
// https://www.w3.org/TR/2012/WD-css3-transforms-20120228/#matrix-decomposition
DCHECK(end_transform);
- return new InterpolatedTransformPropertyValue(
- start_transform, end_transform, progress);
+ return new InterpolatedTransformPropertyValue(start_transform,
+ end_transform, progress);
}
}
} // namespace
@@ -545,7 +556,7 @@
// Try to interpolate each transform function in the transform function
// list. This can only be done if the function types match.
interpolated_value_ = AnimateTransform(start_transform_property_value,
- end_value_, progress_);
+ end_value_, progress_);
}
} else if (end_value_->Equals(*KeywordValue::GetNone())) {
// Interpolate to identity matrix.
@@ -553,8 +564,7 @@
builder.emplace_back(new MatrixFunction(math::Matrix3F::Identity()));
interpolated_value_ = new InterpolatedTransformPropertyValue(
start_transform_property_value,
- new TransformFunctionListValue(std::move(builder)),
- progress_);
+ new TransformFunctionListValue(std::move(builder)), progress_);
} else {
interpolated_value_ = new InterpolatedTransformPropertyValue(
start_transform_property_value,
diff --git a/src/cobalt/cssom/interpolate_property_value_test.cc b/src/cobalt/cssom/interpolate_property_value_test.cc
index 4c49ff1..1550392 100644
--- a/src/cobalt/cssom/interpolate_property_value_test.cc
+++ b/src/cobalt/cssom/interpolate_property_value_test.cc
@@ -133,7 +133,7 @@
}
static scoped_refptr<PropertyValue> End() {
TransformFunctionListValue::Builder functions;
- functions.emplace_back(new CobaltUiNavFocusTransformFunction);
+ functions.emplace_back(new CobaltUiNavFocusTransformFunction(1.0f, 1.0f));
return new TransformFunctionListValue(std::move(functions));
}
};
@@ -149,6 +149,8 @@
dynamic_cast<const CobaltUiNavFocusTransformFunction*>(
interpolated->value()[0].get());
ASSERT_TRUE(focus_function);
+ EXPECT_NEAR(focus_function->x_translation_scale(), 1.0f, kErrorEpsilon);
+ EXPECT_NEAR(focus_function->y_translation_scale(), 1.0f, kErrorEpsilon);
EXPECT_NEAR(focus_function->progress_to_identity(), 0.25f, kErrorEpsilon);
math::Matrix3F value = focus_function->ToMatrix(math::SizeF(), nullptr);
@@ -163,12 +165,14 @@
struct MakeSingleFocusTransform {
static scoped_refptr<PropertyValue> Start() {
TransformFunctionListValue::Builder functions;
- functions.emplace_back(new CobaltUiNavFocusTransformFunction(0.2f));
+ functions.emplace_back(
+ new CobaltUiNavFocusTransformFunction(1.0f, 2.0f, 0.2f));
return new TransformFunctionListValue(std::move(functions));
}
static scoped_refptr<PropertyValue> End() {
TransformFunctionListValue::Builder functions;
- functions.emplace_back(new CobaltUiNavFocusTransformFunction(0.6f));
+ functions.emplace_back(
+ new CobaltUiNavFocusTransformFunction(2.0f, 4.0f, 0.6f));
return new TransformFunctionListValue(std::move(functions));
}
};
@@ -184,6 +188,8 @@
dynamic_cast<const CobaltUiNavFocusTransformFunction*>(
interpolated->value()[0].get());
ASSERT_TRUE(focus_function);
+ EXPECT_NEAR(focus_function->x_translation_scale(), 1.5f, kErrorEpsilon);
+ EXPECT_NEAR(focus_function->y_translation_scale(), 3.0f, kErrorEpsilon);
EXPECT_NEAR(focus_function->progress_to_identity(), 0.4f, kErrorEpsilon);
math::Matrix3F value = focus_function->ToMatrix(math::SizeF(), nullptr);
@@ -720,8 +726,7 @@
0.75f, MakeMultipleMismatchedTransform::Start(),
MakeMultipleMismatchedTransform::End());
EXPECT_TRUE(
- interpolated
- ->ToMatrix(math::SizeF(), nullptr)
+ interpolated->ToMatrix(math::SizeF(), nullptr)
.IsNear(math::TranslateMatrix(3.5f, 0.0f) *
math::RotateMatrix(-static_cast<float>(M_PI * 3 / 8)) *
math::ScaleMatrix(3.5f, 1.75f),
@@ -759,8 +764,7 @@
InterpolatePropertyTyped<InterpolatedTransformPropertyValue>(
0.5f, interpolated, MakeMultipleMismatchedTransform::Start());
- EXPECT_TRUE(next_interpolated
- ->ToMatrix(math::SizeF(), nullptr)
+ EXPECT_TRUE(next_interpolated->ToMatrix(math::SizeF(), nullptr)
.IsNear(math::RotateMatrix(-static_cast<float>(M_PI / 8)),
kErrorEpsilon));
}
@@ -832,8 +836,8 @@
0.5f, MakeMultipleMismatchedTransform::Start(),
MakeMultipleMismatchedTransform::End());
- math::Matrix3F value = interpolated->ToMatrix(
- math::SizeF(100.0f, 200.0f), nullptr);
+ math::Matrix3F value =
+ interpolated->ToMatrix(math::SizeF(100.0f, 200.0f), nullptr);
EXPECT_NEAR(cos(M_PI / 4), value(0, 0), kErrorEpsilon);
EXPECT_NEAR(sin(M_PI / 4), value(1, 0), kErrorEpsilon);
diff --git a/src/cobalt/cssom/property_value_is_equal_test.cc b/src/cobalt/cssom/property_value_is_equal_test.cc
index ec073bb..5d64235 100644
--- a/src/cobalt/cssom/property_value_is_equal_test.cc
+++ b/src/cobalt/cssom/property_value_is_equal_test.cc
@@ -81,17 +81,24 @@
}
TEST(PropertyValueIsEqualTest, CobaltUiNavFocusTransformFunctionsAreEqual) {
- CobaltUiNavFocusTransformFunction function_a;
- CobaltUiNavFocusTransformFunction function_b;
+ CobaltUiNavFocusTransformFunction function_a(1.0f, 1.0f);
+ CobaltUiNavFocusTransformFunction function_b(1.0f, 1.0f);
EXPECT_TRUE(function_a.Equals(function_b));
}
TEST(PropertyValueIsEqualTest, CobaltUiNavFocusTransformFunctionsAreNotEqual) {
- CobaltUiNavFocusTransformFunction function_a(0.0f);
- CobaltUiNavFocusTransformFunction function_b(1.0f);
+ CobaltUiNavFocusTransformFunction function_a(1.0f, 1.0f, 1.0f);
+ CobaltUiNavFocusTransformFunction function_b(1.0f, 1.0f, 0.0f);
+ CobaltUiNavFocusTransformFunction function_c(1.0f, 2.0f, 1.0f);
+ CobaltUiNavFocusTransformFunction function_d(2.0f, 1.0f, 1.0f);
EXPECT_FALSE(function_a.Equals(function_b));
+ EXPECT_FALSE(function_a.Equals(function_c));
+ EXPECT_FALSE(function_a.Equals(function_d));
+ EXPECT_FALSE(function_b.Equals(function_c));
+ EXPECT_FALSE(function_b.Equals(function_d));
+ EXPECT_FALSE(function_c.Equals(function_d));
}
TEST(PropertyValueIsEqualTest, CobaltUiNavSpotlightTransformFunctionsAreEqual) {
@@ -166,17 +173,14 @@
}
TEST(PropertyValueIsEqualTest, LengthsAreEqual) {
- scoped_refptr<LengthValue> value_a(
- new LengthValue(1.5f, kPixelsUnit));
- scoped_refptr<LengthValue> value_b(
- new LengthValue(1.5f, kPixelsUnit));
+ scoped_refptr<LengthValue> value_a(new LengthValue(1.5f, kPixelsUnit));
+ scoped_refptr<LengthValue> value_b(new LengthValue(1.5f, kPixelsUnit));
EXPECT_TRUE(value_a->Equals(*value_b));
}
TEST(PropertyValueIsEqualTest, LengthsAreNotEqual) {
- scoped_refptr<LengthValue> value_a(
- new LengthValue(1.5f, kPixelsUnit));
+ scoped_refptr<LengthValue> value_a(new LengthValue(1.5f, kPixelsUnit));
scoped_refptr<LengthValue> value_b(
new LengthValue(1.5f, kFontSizesAkaEmUnit));
diff --git a/src/cobalt/cssom/property_value_to_string_test.cc b/src/cobalt/cssom/property_value_to_string_test.cc
index 7dc1476..609e2b2 100644
--- a/src/cobalt/cssom/property_value_to_string_test.cc
+++ b/src/cobalt/cssom/property_value_to_string_test.cc
@@ -343,8 +343,8 @@
}
TEST(PropertyValueToStringTest, CobaltUiNavFocusTransformFunction) {
- CobaltUiNavFocusTransformFunction function;
- EXPECT_EQ(function.ToString(), "-cobalt-ui-nav-focus-transform()");
+ CobaltUiNavFocusTransformFunction function(0.5f, 1.0f);
+ EXPECT_EQ(function.ToString(), "-cobalt-ui-nav-focus-transform(0.5, 1)");
}
TEST(PropertyValueToStringTest, CobaltUiNavSpotlightTransformFunction) {
@@ -362,8 +362,9 @@
scoped_refptr<TransformFunctionListValue> property(
new TransformFunctionListValue(std::move(transform_list)));
- EXPECT_EQ(property->ToString(), "translateX(1px) scale(2, 2) rotate(1rad) "
- "-cobalt-ui-nav-spotlight-transform()");
+ EXPECT_EQ(property->ToString(),
+ "translateX(1px) scale(2, 2) rotate(1rad) "
+ "-cobalt-ui-nav-spotlight-transform()");
}
TEST(PropertyValueToStringTest, URLValue) {
diff --git a/src/cobalt/cssom/transform_function_visitor_test.cc b/src/cobalt/cssom/transform_function_visitor_test.cc
index 7ca695f..2fd05a5 100644
--- a/src/cobalt/cssom/transform_function_visitor_test.cc
+++ b/src/cobalt/cssom/transform_function_visitor_test.cc
@@ -63,26 +63,25 @@
}
TEST(TransformFunctionVisitorTest, VisitsTranslateXFunction) {
- TranslateFunction translate_function(
- TranslateFunction::kXAxis, new LengthValue(0, kPixelsUnit));
+ TranslateFunction translate_function(TranslateFunction::kXAxis,
+ new LengthValue(0, kPixelsUnit));
MockTransformFunctionVisitor mock_visitor;
EXPECT_CALL(mock_visitor, VisitTranslate(&translate_function));
translate_function.Accept(&mock_visitor);
}
TEST(TransformFunctionVisitorTest, VisitsCobaltUiNavFocusTransform) {
- CobaltUiNavFocusTransformFunction focus_function;
+ CobaltUiNavFocusTransformFunction focus_function(1.0f, 1.0f);
MockTransformFunctionVisitor mock_visitor;
- EXPECT_CALL(mock_visitor, VisitCobaltUiNavFocusTransform(
- &focus_function));
+ EXPECT_CALL(mock_visitor, VisitCobaltUiNavFocusTransform(&focus_function));
focus_function.Accept(&mock_visitor);
}
TEST(TransformFunctionVisitorTest, VisitsCobaltUiNavSpotlightTransform) {
CobaltUiNavSpotlightTransformFunction spotlight_function;
MockTransformFunctionVisitor mock_visitor;
- EXPECT_CALL(mock_visitor, VisitCobaltUiNavSpotlightTransform(
- &spotlight_function));
+ EXPECT_CALL(mock_visitor,
+ VisitCobaltUiNavSpotlightTransform(&spotlight_function));
spotlight_function.Accept(&mock_visitor);
}
diff --git a/src/cobalt/demos/content/media-element-demo/README.md b/src/cobalt/demos/content/media-element-demo/README.md
new file mode 100644
index 0000000..ee731e2
--- /dev/null
+++ b/src/cobalt/demos/content/media-element-demo/README.md
@@ -0,0 +1,27 @@
+# Cobalt Media Demo
+
+## Installation
+
+```bash
+# Install node modules
+npm install
+```
+Only needed for the first time.
+
+## Development
+
+```bash
+# Start an http server and build the package
+npm start
+```
+
+It watches script changes and recompiles the script bundle.
+
+
+## Deploy
+```bash
+# Compiles the script bundle.
+npm run build
+```
+
+Copy all files under `dist/` folder to the server.
diff --git a/src/cobalt/demos/content/media-element-demo/README.txt b/src/cobalt/demos/content/media-element-demo/README.txt
deleted file mode 100644
index 6b09933..0000000
--- a/src/cobalt/demos/content/media-element-demo/README.txt
+++ /dev/null
@@ -1,2 +0,0 @@
-The content of this folder no longer works as local files as the media files
-have to be served in a web server in order to make it work with XMLHttpRequest.
diff --git a/src/cobalt/demos/content/media-element-demo/key-systems.html b/src/cobalt/demos/content/media-element-demo/legacy/key-systems.html
similarity index 100%
rename from src/cobalt/demos/content/media-element-demo/key-systems.html
rename to src/cobalt/demos/content/media-element-demo/legacy/key-systems.html
diff --git a/src/cobalt/demos/content/media-element-demo/key-systems.js b/src/cobalt/demos/content/media-element-demo/legacy/key-systems.js
similarity index 100%
rename from src/cobalt/demos/content/media-element-demo/key-systems.js
rename to src/cobalt/demos/content/media-element-demo/legacy/key-systems.js
diff --git a/src/cobalt/demos/content/media-element-demo/loop-playback.html b/src/cobalt/demos/content/media-element-demo/loop-playback.html
deleted file mode 100644
index 91b04c0..0000000
--- a/src/cobalt/demos/content/media-element-demo/loop-playback.html
+++ /dev/null
@@ -1,20 +0,0 @@
-<!DOCTYPE html>
-<html>
-<head>
- <title>Loop Playback</title>
- <style>
- body {
- background-color: rgb(255, 255, 255);
- color: #0047ab;
- font-size: 100px;
- }
- video {
- transform: translateX(100px) rotate(3deg);
- }
- </style>
-</head>
-<body>
- Loop Playback
- <script type="text/javascript" src="loop-playback.js"></script>
-</body>
-</html>
diff --git a/src/cobalt/demos/content/media-element-demo/loop-playback.js b/src/cobalt/demos/content/media-element-demo/loop-playback.js
deleted file mode 100644
index b100d12..0000000
--- a/src/cobalt/demos/content/media-element-demo/loop-playback.js
+++ /dev/null
@@ -1,127 +0,0 @@
-// Copyright 2018 The Cobalt Authors. 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 page simply plays an audio or a video stream in a loop, it can be used
-// in the following forms:
-// loop-playback.html?url=video.mp4&type=progressive
-// loop-playback.html?url=video.webm&type=video
-// loop-playback.html?url=audio.mp4&type=audio
-// If the stream is adaptive, it has to be fit in memory as this demo will
-// download the whole stream at once.
-
-var video = null;
-var url = null;
-var type = null;
-
-function downloadAndAppend(source_buffer, callback) {
- var xhr = new XMLHttpRequest;
- xhr.open('GET', url, true);
- xhr.responseType = 'arraybuffer';
- xhr.addEventListener('load', function(e) {
- var onupdateend = function() {
- source_buffer.removeEventListener('updateend', onupdateend);
- callback();
- };
- source_buffer.addEventListener('updateend', onupdateend);
- source_buffer.appendBuffer(new Uint8Array(e.target.response));
- });
- xhr.send();
-}
-
-function createVideoElement() {
- var video = document.createElement('video');
- video.autoplay = true;
- video.style.width = '1280px';
- video.style.height = '720px';
- document.body.appendChild(video);
-
- return video;
-}
-
-function onVideoEnded() {
- console.log('playback ended');
- startNextVideo();
-}
-
-function startProgressiveVideo() {
- video.src = '';
- video.load();
- video.src = url;
- video.addEventListener('ended', onVideoEnded.bind());
-}
-
-function startAdaptiveVideo() {
- video.src = '';
- video.load();
- var mediasource = new MediaSource;
- mediasource.addEventListener('sourceopen', function () {
- var source_buffer;
- if (type == "audio") {
- if (url.indexOf(".mp4") != -1) {
- source_buffer = mediasource.addSourceBuffer('audio/mp4; codecs="mp4a.40.2"');
- } else if (url.indexOf(".webm") != -1) {
- source_buffer = mediasource.addSourceBuffer('audio/webm; codecs="opus"');
- } else {
- throw "unknown audio format " + url;
- }
- } else {
- if (url.indexOf(".mp4") != -1) {
- source_buffer = mediasource.addSourceBuffer('video/mp4; codecs="avc1.640028"');
- } else if (url.indexOf(".webm") != -1) {
- source_buffer = mediasource.addSourceBuffer('video/webm; codecs="vp9"');
- } else {
- throw "unknown video format " + url;
- }
- }
- downloadAndAppend(source_buffer, function () {
- mediasource.endOfStream();
- });
- })
-
- video.src = window.URL.createObjectURL(mediasource);
- video.addEventListener('ended', onVideoEnded);
-}
-
-function startNextVideo() {
- if (type == "progressive") {
- startProgressiveVideo();
- } else {
- startAdaptiveVideo();
- }
-}
-
-function main() {
- var get_parameters = window.location.search.substr(1).split('&');
- for (var param of get_parameters) {
- splitted = param.split('=');
- if (splitted[0] == 'url') {
- url = splitted[1];
- } else if (splitted[0] == 'type') {
- type = splitted[1];
- }
- }
-
- if (!url) {
- throw "url is not set.";
- }
-
- if (type != 'progressive' && type != 'audio' && type != 'video') {
- throw "invalid type " + type;
- }
-
- video = createVideoElement();
- startNextVideo();
-}
-
-main();
diff --git a/src/cobalt/demos/content/media-element-demo/media-element-demo.html b/src/cobalt/demos/content/media-element-demo/media-element-demo.html
deleted file mode 100644
index 665d953..0000000
--- a/src/cobalt/demos/content/media-element-demo/media-element-demo.html
+++ /dev/null
@@ -1,20 +0,0 @@
-<!DOCTYPE html>
-<html>
-<head>
- <title>Media Element Demo</title>
- <style>
- body {
- background-color: rgb(255, 255, 255);
- color: #0047ab;
- font-size: 100px;
- }
- video {
- transform: translateX(100px) rotate(3deg);
- }
- </style>
-</head>
-<body>
- Media Element Demo
- <script type="text/javascript" src="media-element-demo.js"></script>
-</body>
-</html>
diff --git a/src/cobalt/demos/content/media-element-demo/media-element-demo.js b/src/cobalt/demos/content/media-element-demo/media-element-demo.js
deleted file mode 100644
index 73cea11..0000000
--- a/src/cobalt/demos/content/media-element-demo/media-element-demo.js
+++ /dev/null
@@ -1,125 +0,0 @@
-// Copyright 2015 The Cobalt Authors. 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 demo does the following steps in a loop:
-// 1. Playback a progressive video.
-// 2. Playback a section of a 240p video in adaptive (DASH).
-// 3. Playback the above 240p video in 1080p.
-// All above videos have audio accompanied.
-
-// Description of the streams being played.
-var kProgressiveVideoUrl = 'progressive.mp4';
-
-var kAdaptiveVideoUrl_240p = 'dash-video-240p.mp4';
-var kAdaptiveVideoSize_240p = 2051611;
-// The size of the video that can be played for 10s.
-var kAdaptiveVideo10sChunkSize_240p = 306689;
-
-var kAdaptiveVideoUrl_1080p = 'dash-video-1080p.mp4';
-var kAdaptiveVideoSize_1080p = 22461669;
-
-var kAdaptiveAudioUrl = 'dash-audio.mp4';
-var kAdaptiveAudioSize = 1048531;
-var kAdaptiveAudioChunkSize = 720 * 1024;
-
-var is_progressive = false;
-var video = null;
-
-// Send a range request of [`begin`, `end`] (inclusive) to download content from
-// the `url` and append the downloaded content into the `source_buffer` before
-// calling the `callback` function.
-function downloadAndAppend(url, begin, end, source_buffer, callback) {
- var xhr = new XMLHttpRequest;
- xhr.open('GET', url, true);
- xhr.responseType = 'arraybuffer';
- xhr.addEventListener('load', function(e) {
- var onupdateend = function() {
- source_buffer.removeEventListener('updateend', onupdateend);
- callback();
- };
- source_buffer.addEventListener('updateend', onupdateend);
- source_buffer.appendBuffer(new Uint8Array(e.target.response));
- });
- xhr.setRequestHeader('Range', ('bytes=' + begin +'-' + end));
- xhr.send();
-}
-
-function createVideoElement() {
- var video = document.createElement('video');
- video.autoplay = true;
- video.style.width = '1280px';
- video.style.height = '720px';
- document.body.appendChild(video);
-
- return video;
-}
-
-function createStatusElement(video) {
- var status = document.createElement('div');
- document.body.appendChild(status);
- video.addEventListener('timeupdate', function () {
- status.textContent = is_progressive ? 'Progressive' : 'Adaptive';
- status.textContent += ' / time: ' + video.currentTime.toFixed(2);
- });
-
- return status;
-}
-
-function onVideoEnded() {
- console.log('ended');
- is_progressive = !is_progressive;
- startNextVideo();
-}
-
-function startProgressiveVideo(video) {
- video.src = '';
- video.load();
- video.src = kProgressiveVideoUrl;
- video.addEventListener('ended', onVideoEnded);
-}
-
-function startAdaptiveVideo(video) {
- video.src = '';
- video.load();
- var mediasource = new MediaSource;
- mediasource.addEventListener('sourceopen', function () {
- var video_source_buffer = mediasource.addSourceBuffer('video/mp4; codecs="avc1.640028"');
- var audio_source_buffer = mediasource.addSourceBuffer('audio/mp4; codecs="mp4a.40.2"');
- downloadAndAppend('dash-video-1080p.mp4', 0, 15 * 1024 * 1024, video_source_buffer, function () {
- video_source_buffer.abort();
- // Append the first two segments of the 240p video so we can see the transition.
- downloadAndAppend('dash-video-240p.mp4', 0, kAdaptiveVideo10sChunkSize_240p, video_source_buffer, function () {
- video_source_buffer.abort();
- downloadAndAppend('dash-audio.mp4', 0, kAdaptiveAudioChunkSize, audio_source_buffer, function () {
- mediasource.endOfStream();
- });
- });
- });
- })
-
- video.src = window.URL.createObjectURL(mediasource);
- video.addEventListener('ended', onVideoEnded);
-}
-
-function startNextVideo() {
- if (is_progressive) {
- startProgressiveVideo(video);
- } else {
- startAdaptiveVideo(video);
- }
-}
-
-video = createVideoElement();
-createStatusElement(video);
-startNextVideo(video);
diff --git a/src/cobalt/demos/content/media-element-demo/multi-video-demo.html b/src/cobalt/demos/content/media-element-demo/multi-video-demo.html
deleted file mode 100644
index e79f36b..0000000
--- a/src/cobalt/demos/content/media-element-demo/multi-video-demo.html
+++ /dev/null
@@ -1,19 +0,0 @@
-<!DOCTYPE html>
-<html>
-<head>
- <title>Multi Video Demo</title>
- <style>
- body {
- background-color: rgb(255, 255, 255);
- color: #0047ab;
- font-size: 10px;
- }
- video {
- transform: translateX(100px) rotate(3deg);
- }
- </style>
-</head>
-<body>
- <script type="text/javascript" src="multi-video-demo.js"></script>
-</body>
-</html>
diff --git a/src/cobalt/demos/content/media-element-demo/multi-video-demo.js b/src/cobalt/demos/content/media-element-demo/multi-video-demo.js
deleted file mode 100644
index cab4d58..0000000
--- a/src/cobalt/demos/content/media-element-demo/multi-video-demo.js
+++ /dev/null
@@ -1,197 +0,0 @@
-// Copyright 2018 The Cobalt Authors. 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 demo simply plays a video using get parameters in the form of:
-// .../multi-video-demo.html?audio=filename_in_same_folder&video=filename_in_same_folder&instances=2
-
-var kAudioChunkSize = 512 * 1024;
-var kVideoChunkSize = 2 * 1024 * 1024;
-
-var kEndOfStreamOffset = -1;
-
-class Player {
- constructor(audio_url, video_url) {
- this.audio_offset = 0;
- this.audio_url = audio_url;
- this.video_offset = 0;
- this.video_url = video_url;
- this.video_tag = this.createVideoElement();
- this.status = this.createStatusElement(this.video_tag);
-
- this.video_tag.src = '';
- this.video_tag.load();
- this.mediasource = new MediaSource;
- this.mediasource.addEventListener('sourceopen', this.onsourceopen.bind(this));
- this.video_tag.src = window.URL.createObjectURL(this.mediasource);
- }
-
- onsourceopen() {
- if (this.video_url.endsWith('.mp4')) {
- this.video_source_buffer = this.mediasource.addSourceBuffer(
- 'video/mp4; codecs="avc1.640028"');
- } else {
- this.video_source_buffer = this.mediasource.addSourceBuffer(
- 'video/webm; codecs="vp9"');
- }
-
- this.audio_source_buffer = this.mediasource.addSourceBuffer(
- 'audio/mp4; codecs="mp4a.40.2"');
- this.tryToDownloadAudioData();
- }
-
- downloadAndAppend(url, begin, end, source_buffer, callback) {
- var xhr = new XMLHttpRequest;
- xhr.open('GET', url, true);
- xhr.responseType = 'arraybuffer';
- xhr.addEventListener('load', function(e) {
- var data = new Uint8Array(e.target.response);
- var onupdateend = function() {
- source_buffer.removeEventListener('updateend', onupdateend);
- callback(data.length);
- };
- source_buffer.addEventListener('updateend', onupdateend);
- source_buffer.appendBuffer(data);
- console.log('append ' + data.length + ' bytes from '
- + url);
- });
- xhr.setRequestHeader('Range', ('bytes=' + begin +'-' + end));
- xhr.send();
- }
-
- isTrackNeedAudioData() {
- if (this.audio_offset == kEndOfStreamOffset) {
- return false;
- }
- var buffer_range_size = this.audio_source_buffer.buffered.length;
- if (buffer_range_size == 0) {
- return true;
- }
- var start = this.audio_source_buffer.buffered.start(buffer_range_size - 1);
- var end = this.audio_source_buffer.buffered.end(buffer_range_size - 1);
- console.log('audio ' + start + '/' + end + ' ' + this.video_tag.currentTime)
- return end - this.video_tag.currentTime <= 20;
- }
-
- isTrackNeedVideoData() {
- if (this.video_offset == kEndOfStreamOffset) {
- return false;
- }
- var buffer_range_size = this.video_source_buffer.buffered.length;
- if (buffer_range_size == 0) {
- return true;
- }
- var start = this.video_source_buffer.buffered.start(buffer_range_size - 1);
- var end = this.video_source_buffer.buffered.end(buffer_range_size - 1);
- console.log('video ' + start + '/' + end + ' ' + this.video_tag.currentTime)
- return end - this.video_tag.currentTime <= 20;
- }
-
- tryToDownloadAudioData() {
- if (!this.isTrackNeedAudioData()) {
- if (this.isTrackNeedVideoData()) {
- this.tryToDownloadVideoData();
- } else {
- window.setTimeout(this.tryToDownloadAudioData.bind(this), 1000);
- }
- return;
- }
-
- this.downloadAndAppend(
- this.audio_url, this.audio_offset,
- this.audio_offset + kAudioChunkSize - 1, this.audio_source_buffer,
- this.onAudioDataDownloaded.bind(this));
- }
-
- onAudioDataDownloaded(length) {
- if (length != kAudioChunkSize) {
- this.audio_offset = kEndOfStreamOffset;
- }
- if (this.audio_offset != kEndOfStreamOffset) {
- this.audio_offset += kAudioChunkSize;
- }
- this.tryToDownloadVideoData();
- }
-
- tryToDownloadVideoData() {
- if (!this.isTrackNeedVideoData()) {
- if (this.isTrackNeedAudioData()) {
- this.tryToDownloadAudioData();
- } else {
- window.setTimeout(this.tryToDownloadVideoData.bind(this), 1000);
- }
- return;
- }
-
- this.downloadAndAppend(
- this.video_url, this.video_offset,
- this.video_offset + kVideoChunkSize - 1, this.video_source_buffer,
- this.onVideoDataDownloaded.bind(this));
- }
-
- onVideoDataDownloaded(length) {
- if (length != kVideoChunkSize) {
- this.video_offset = kEndOfStreamOffset;
- }
- if (this.video_offset != kEndOfStreamOffset) {
- this.video_offset += kVideoChunkSize;
- }
- this.tryToDownloadAudioData();
- }
-
- createVideoElement() {
- var video = document.createElement('video');
- video.autoplay = true;
- video.style.width = '320px';
- video.style.height = '240px';
- document.body.appendChild(video);
-
- return video;
- }
-
- createStatusElement(video) {
- var status = document.createElement('div');
- document.body.appendChild(status);
- video.addEventListener('timeupdate', function () {
- status.textContent = 'time: ' + video.currentTime.toFixed(2);
- });
-
- return status;
- }
-}
-
-function main() {
- var get_parameters = window.location.search.substr(1).split('&');
- var audio_url, video_url, instances = 2;
- for (var param of get_parameters) {
- splitted = param.split('=');
- if (splitted[0] == 'audio') {
- audio_url = splitted[1];
- } else if (splitted[0] == 'video') {
- video_url = splitted[1];
- } else if (splitted[0] == 'instances') {
- instances = splitted[1];
- }
- }
-
- if (audio_url && video_url) {
- for (var i = 0; i < instances; ++i) {
- new Player(audio_url, video_url);
- }
- } else {
- status.textContent = "invalid get parameters " +
- window.location.search.substr(1);
- }
-}
-
-main();
diff --git a/src/cobalt/demos/content/media-element-demo/package-lock.json b/src/cobalt/demos/content/media-element-demo/package-lock.json
new file mode 100644
index 0000000..698b6f8
--- /dev/null
+++ b/src/cobalt/demos/content/media-element-demo/package-lock.json
@@ -0,0 +1,4395 @@
+{
+ "name": "media-element-demo",
+ "version": "1.0.0",
+ "lockfileVersion": 1,
+ "requires": true,
+ "dependencies": {
+ "@nodelib/fs.scandir": {
+ "version": "2.1.3",
+ "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.3.tgz",
+ "integrity": "sha512-eGmwYQn3gxo4r7jdQnkrrN6bY478C3P+a/y72IJukF8LjB6ZHeB3c+Ehacj3sYeSmUXGlnA67/PmbM9CVwL7Dw==",
+ "dev": true,
+ "requires": {
+ "@nodelib/fs.stat": "2.0.3",
+ "run-parallel": "^1.1.9"
+ }
+ },
+ "@nodelib/fs.stat": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.3.tgz",
+ "integrity": "sha512-bQBFruR2TAwoevBEd/NWMoAAtNGzTRgdrqnYCc7dhzfoNvqPzLyqlEQnzZ3kVnNrSp25iyxE00/3h2fqGAGArA==",
+ "dev": true
+ },
+ "@nodelib/fs.walk": {
+ "version": "1.2.4",
+ "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.4.tgz",
+ "integrity": "sha512-1V9XOY4rDW0rehzbrcqAmHnz8e7SKvX27gh8Gt2WgB0+pdzdiLV83p72kZPU+jvMbS1qU5mauP2iOvO8rhmurQ==",
+ "dev": true,
+ "requires": {
+ "@nodelib/fs.scandir": "2.1.3",
+ "fastq": "^1.6.0"
+ }
+ },
+ "@npmcli/move-file": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/@npmcli/move-file/-/move-file-1.0.1.tgz",
+ "integrity": "sha512-Uv6h1sT+0DrblvIrolFtbvM1FgWm+/sy4B3pvLp67Zys+thcukzS5ekn7HsZFGpWP4Q3fYJCljbWQE/XivMRLw==",
+ "dev": true,
+ "requires": {
+ "mkdirp": "^1.0.4"
+ },
+ "dependencies": {
+ "mkdirp": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz",
+ "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==",
+ "dev": true
+ }
+ }
+ },
+ "@types/json-schema": {
+ "version": "7.0.6",
+ "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.6.tgz",
+ "integrity": "sha512-3c+yGKvVP5Y9TYBEibGNR+kLtijnj7mYrXRg+WpFb2X9xm04g/DXYkfg4hmzJQosc9snFNUPkbYIhu+KAm6jJw==",
+ "dev": true
+ },
+ "@webassemblyjs/ast": {
+ "version": "1.9.0",
+ "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.9.0.tgz",
+ "integrity": "sha512-C6wW5L+b7ogSDVqymbkkvuW9kruN//YisMED04xzeBBqjHa2FYnmvOlS6Xj68xWQRgWvI9cIglsjFowH/RJyEA==",
+ "dev": true,
+ "requires": {
+ "@webassemblyjs/helper-module-context": "1.9.0",
+ "@webassemblyjs/helper-wasm-bytecode": "1.9.0",
+ "@webassemblyjs/wast-parser": "1.9.0"
+ }
+ },
+ "@webassemblyjs/floating-point-hex-parser": {
+ "version": "1.9.0",
+ "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.9.0.tgz",
+ "integrity": "sha512-TG5qcFsS8QB4g4MhrxK5TqfdNe7Ey/7YL/xN+36rRjl/BlGE/NcBvJcqsRgCP6Z92mRE+7N50pRIi8SmKUbcQA==",
+ "dev": true
+ },
+ "@webassemblyjs/helper-api-error": {
+ "version": "1.9.0",
+ "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.9.0.tgz",
+ "integrity": "sha512-NcMLjoFMXpsASZFxJ5h2HZRcEhDkvnNFOAKneP5RbKRzaWJN36NC4jqQHKwStIhGXu5mUWlUUk7ygdtrO8lbmw==",
+ "dev": true
+ },
+ "@webassemblyjs/helper-buffer": {
+ "version": "1.9.0",
+ "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.9.0.tgz",
+ "integrity": "sha512-qZol43oqhq6yBPx7YM3m9Bv7WMV9Eevj6kMi6InKOuZxhw+q9hOkvq5e/PpKSiLfyetpaBnogSbNCfBwyB00CA==",
+ "dev": true
+ },
+ "@webassemblyjs/helper-code-frame": {
+ "version": "1.9.0",
+ "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-code-frame/-/helper-code-frame-1.9.0.tgz",
+ "integrity": "sha512-ERCYdJBkD9Vu4vtjUYe8LZruWuNIToYq/ME22igL+2vj2dQ2OOujIZr3MEFvfEaqKoVqpsFKAGsRdBSBjrIvZA==",
+ "dev": true,
+ "requires": {
+ "@webassemblyjs/wast-printer": "1.9.0"
+ }
+ },
+ "@webassemblyjs/helper-fsm": {
+ "version": "1.9.0",
+ "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-fsm/-/helper-fsm-1.9.0.tgz",
+ "integrity": "sha512-OPRowhGbshCb5PxJ8LocpdX9Kl0uB4XsAjl6jH/dWKlk/mzsANvhwbiULsaiqT5GZGT9qinTICdj6PLuM5gslw==",
+ "dev": true
+ },
+ "@webassemblyjs/helper-module-context": {
+ "version": "1.9.0",
+ "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-module-context/-/helper-module-context-1.9.0.tgz",
+ "integrity": "sha512-MJCW8iGC08tMk2enck1aPW+BE5Cw8/7ph/VGZxwyvGbJwjktKkDK7vy7gAmMDx88D7mhDTCNKAW5tED+gZ0W8g==",
+ "dev": true,
+ "requires": {
+ "@webassemblyjs/ast": "1.9.0"
+ }
+ },
+ "@webassemblyjs/helper-wasm-bytecode": {
+ "version": "1.9.0",
+ "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.9.0.tgz",
+ "integrity": "sha512-R7FStIzyNcd7xKxCZH5lE0Bqy+hGTwS3LJjuv1ZVxd9O7eHCedSdrId/hMOd20I+v8wDXEn+bjfKDLzTepoaUw==",
+ "dev": true
+ },
+ "@webassemblyjs/helper-wasm-section": {
+ "version": "1.9.0",
+ "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.9.0.tgz",
+ "integrity": "sha512-XnMB8l3ek4tvrKUUku+IVaXNHz2YsJyOOmz+MMkZvh8h1uSJpSen6vYnw3IoQ7WwEuAhL8Efjms1ZWjqh2agvw==",
+ "dev": true,
+ "requires": {
+ "@webassemblyjs/ast": "1.9.0",
+ "@webassemblyjs/helper-buffer": "1.9.0",
+ "@webassemblyjs/helper-wasm-bytecode": "1.9.0",
+ "@webassemblyjs/wasm-gen": "1.9.0"
+ }
+ },
+ "@webassemblyjs/ieee754": {
+ "version": "1.9.0",
+ "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.9.0.tgz",
+ "integrity": "sha512-dcX8JuYU/gvymzIHc9DgxTzUUTLexWwt8uCTWP3otys596io0L5aW02Gb1RjYpx2+0Jus1h4ZFqjla7umFniTg==",
+ "dev": true,
+ "requires": {
+ "@xtuc/ieee754": "^1.2.0"
+ }
+ },
+ "@webassemblyjs/leb128": {
+ "version": "1.9.0",
+ "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.9.0.tgz",
+ "integrity": "sha512-ENVzM5VwV1ojs9jam6vPys97B/S65YQtv/aanqnU7D8aSoHFX8GyhGg0CMfyKNIHBuAVjy3tlzd5QMMINa7wpw==",
+ "dev": true,
+ "requires": {
+ "@xtuc/long": "4.2.2"
+ }
+ },
+ "@webassemblyjs/utf8": {
+ "version": "1.9.0",
+ "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.9.0.tgz",
+ "integrity": "sha512-GZbQlWtopBTP0u7cHrEx+73yZKrQoBMpwkGEIqlacljhXCkVM1kMQge/Mf+csMJAjEdSwhOyLAS0AoR3AG5P8w==",
+ "dev": true
+ },
+ "@webassemblyjs/wasm-edit": {
+ "version": "1.9.0",
+ "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.9.0.tgz",
+ "integrity": "sha512-FgHzBm80uwz5M8WKnMTn6j/sVbqilPdQXTWraSjBwFXSYGirpkSWE2R9Qvz9tNiTKQvoKILpCuTjBKzOIm0nxw==",
+ "dev": true,
+ "requires": {
+ "@webassemblyjs/ast": "1.9.0",
+ "@webassemblyjs/helper-buffer": "1.9.0",
+ "@webassemblyjs/helper-wasm-bytecode": "1.9.0",
+ "@webassemblyjs/helper-wasm-section": "1.9.0",
+ "@webassemblyjs/wasm-gen": "1.9.0",
+ "@webassemblyjs/wasm-opt": "1.9.0",
+ "@webassemblyjs/wasm-parser": "1.9.0",
+ "@webassemblyjs/wast-printer": "1.9.0"
+ }
+ },
+ "@webassemblyjs/wasm-gen": {
+ "version": "1.9.0",
+ "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.9.0.tgz",
+ "integrity": "sha512-cPE3o44YzOOHvlsb4+E9qSqjc9Qf9Na1OO/BHFy4OI91XDE14MjFN4lTMezzaIWdPqHnsTodGGNP+iRSYfGkjA==",
+ "dev": true,
+ "requires": {
+ "@webassemblyjs/ast": "1.9.0",
+ "@webassemblyjs/helper-wasm-bytecode": "1.9.0",
+ "@webassemblyjs/ieee754": "1.9.0",
+ "@webassemblyjs/leb128": "1.9.0",
+ "@webassemblyjs/utf8": "1.9.0"
+ }
+ },
+ "@webassemblyjs/wasm-opt": {
+ "version": "1.9.0",
+ "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.9.0.tgz",
+ "integrity": "sha512-Qkjgm6Anhm+OMbIL0iokO7meajkzQD71ioelnfPEj6r4eOFuqm4YC3VBPqXjFyyNwowzbMD+hizmprP/Fwkl2A==",
+ "dev": true,
+ "requires": {
+ "@webassemblyjs/ast": "1.9.0",
+ "@webassemblyjs/helper-buffer": "1.9.0",
+ "@webassemblyjs/wasm-gen": "1.9.0",
+ "@webassemblyjs/wasm-parser": "1.9.0"
+ }
+ },
+ "@webassemblyjs/wasm-parser": {
+ "version": "1.9.0",
+ "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.9.0.tgz",
+ "integrity": "sha512-9+wkMowR2AmdSWQzsPEjFU7njh8HTO5MqO8vjwEHuM+AMHioNqSBONRdr0NQQ3dVQrzp0s8lTcYqzUdb7YgELA==",
+ "dev": true,
+ "requires": {
+ "@webassemblyjs/ast": "1.9.0",
+ "@webassemblyjs/helper-api-error": "1.9.0",
+ "@webassemblyjs/helper-wasm-bytecode": "1.9.0",
+ "@webassemblyjs/ieee754": "1.9.0",
+ "@webassemblyjs/leb128": "1.9.0",
+ "@webassemblyjs/utf8": "1.9.0"
+ }
+ },
+ "@webassemblyjs/wast-parser": {
+ "version": "1.9.0",
+ "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-parser/-/wast-parser-1.9.0.tgz",
+ "integrity": "sha512-qsqSAP3QQ3LyZjNC/0jBJ/ToSxfYJ8kYyuiGvtn/8MK89VrNEfwj7BPQzJVHi0jGTRK2dGdJ5PRqhtjzoww+bw==",
+ "dev": true,
+ "requires": {
+ "@webassemblyjs/ast": "1.9.0",
+ "@webassemblyjs/floating-point-hex-parser": "1.9.0",
+ "@webassemblyjs/helper-api-error": "1.9.0",
+ "@webassemblyjs/helper-code-frame": "1.9.0",
+ "@webassemblyjs/helper-fsm": "1.9.0",
+ "@xtuc/long": "4.2.2"
+ }
+ },
+ "@webassemblyjs/wast-printer": {
+ "version": "1.9.0",
+ "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.9.0.tgz",
+ "integrity": "sha512-2J0nE95rHXHyQ24cWjMKJ1tqB/ds8z/cyeOZxJhcb+rW+SQASVjuznUSmdz5GpVJTzU8JkhYut0D3siFDD6wsA==",
+ "dev": true,
+ "requires": {
+ "@webassemblyjs/ast": "1.9.0",
+ "@webassemblyjs/wast-parser": "1.9.0",
+ "@xtuc/long": "4.2.2"
+ }
+ },
+ "@xtuc/ieee754": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz",
+ "integrity": "sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==",
+ "dev": true
+ },
+ "@xtuc/long": {
+ "version": "4.2.2",
+ "resolved": "https://registry.npmjs.org/@xtuc/long/-/long-4.2.2.tgz",
+ "integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==",
+ "dev": true
+ },
+ "acorn": {
+ "version": "6.4.2",
+ "resolved": "https://registry.npmjs.org/acorn/-/acorn-6.4.2.tgz",
+ "integrity": "sha512-XtGIhXwF8YM8bJhGxG5kXgjkEuNGLTkoYqVE+KMR+aspr4KGYmKYg7yUe3KghyQ9yheNwLnjmzh/7+gfDBmHCQ==",
+ "dev": true
+ },
+ "aggregate-error": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz",
+ "integrity": "sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==",
+ "dev": true,
+ "requires": {
+ "clean-stack": "^2.0.0",
+ "indent-string": "^4.0.0"
+ }
+ },
+ "ajv": {
+ "version": "6.12.6",
+ "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
+ "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==",
+ "dev": true,
+ "requires": {
+ "fast-deep-equal": "^3.1.1",
+ "fast-json-stable-stringify": "^2.0.0",
+ "json-schema-traverse": "^0.4.1",
+ "uri-js": "^4.2.2"
+ }
+ },
+ "ajv-errors": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/ajv-errors/-/ajv-errors-1.0.1.tgz",
+ "integrity": "sha512-DCRfO/4nQ+89p/RK43i8Ezd41EqdGIU4ld7nGF8OQ14oc/we5rEntLCUa7+jrn3nn83BosfwZA0wb4pon2o8iQ==",
+ "dev": true
+ },
+ "ajv-keywords": {
+ "version": "3.5.2",
+ "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz",
+ "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==",
+ "dev": true
+ },
+ "ansi-regex": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz",
+ "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==",
+ "dev": true
+ },
+ "ansi-styles": {
+ "version": "3.2.1",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
+ "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
+ "dev": true,
+ "requires": {
+ "color-convert": "^1.9.0"
+ }
+ },
+ "anymatch": {
+ "version": "3.1.1",
+ "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.1.tgz",
+ "integrity": "sha512-mM8522psRCqzV+6LhomX5wgp25YVibjh8Wj23I5RPkPppSVSjyKD2A2mBJmWGa+KN7f2D6LNh9jkBCeyLktzjg==",
+ "dev": true,
+ "optional": true,
+ "requires": {
+ "normalize-path": "^3.0.0",
+ "picomatch": "^2.0.4"
+ }
+ },
+ "aproba": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz",
+ "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==",
+ "dev": true
+ },
+ "arr-diff": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz",
+ "integrity": "sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA=",
+ "dev": true
+ },
+ "arr-flatten": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.1.0.tgz",
+ "integrity": "sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg==",
+ "dev": true
+ },
+ "arr-union": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/arr-union/-/arr-union-3.1.0.tgz",
+ "integrity": "sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ=",
+ "dev": true
+ },
+ "array-union": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz",
+ "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==",
+ "dev": true
+ },
+ "array-unique": {
+ "version": "0.3.2",
+ "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz",
+ "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=",
+ "dev": true
+ },
+ "asn1.js": {
+ "version": "5.4.1",
+ "resolved": "https://registry.npmjs.org/asn1.js/-/asn1.js-5.4.1.tgz",
+ "integrity": "sha512-+I//4cYPccV8LdmBLiX8CYvf9Sp3vQsrqu2QNXRcrbiWvcx/UdlFiqUJJzxRQxgsZmvhXhn4cSKeSmoFjVdupA==",
+ "dev": true,
+ "requires": {
+ "bn.js": "^4.0.0",
+ "inherits": "^2.0.1",
+ "minimalistic-assert": "^1.0.0",
+ "safer-buffer": "^2.1.0"
+ },
+ "dependencies": {
+ "bn.js": {
+ "version": "4.11.9",
+ "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.9.tgz",
+ "integrity": "sha512-E6QoYqCKZfgatHTdHzs1RRKP7ip4vvm+EyRUeE2RF0NblwVvb0p6jSVeNTOFxPn26QXN2o6SMfNxKp6kU8zQaw==",
+ "dev": true
+ }
+ }
+ },
+ "assert": {
+ "version": "1.5.0",
+ "resolved": "https://registry.npmjs.org/assert/-/assert-1.5.0.tgz",
+ "integrity": "sha512-EDsgawzwoun2CZkCgtxJbv392v4nbk9XDD06zI+kQYoBM/3RBWLlEyJARDOmhAAosBjWACEkKL6S+lIZtcAubA==",
+ "dev": true,
+ "requires": {
+ "object-assign": "^4.1.1",
+ "util": "0.10.3"
+ },
+ "dependencies": {
+ "inherits": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz",
+ "integrity": "sha1-sX0I0ya0Qj5Wjv9xn5GwscvfafE=",
+ "dev": true
+ },
+ "util": {
+ "version": "0.10.3",
+ "resolved": "https://registry.npmjs.org/util/-/util-0.10.3.tgz",
+ "integrity": "sha1-evsa/lCAUkZInj23/g7TeTNqwPk=",
+ "dev": true,
+ "requires": {
+ "inherits": "2.0.1"
+ }
+ }
+ }
+ },
+ "assign-symbols": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/assign-symbols/-/assign-symbols-1.0.0.tgz",
+ "integrity": "sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c=",
+ "dev": true
+ },
+ "async": {
+ "version": "2.6.3",
+ "resolved": "https://registry.npmjs.org/async/-/async-2.6.3.tgz",
+ "integrity": "sha512-zflvls11DCy+dQWzTW2dzuilv8Z5X/pjfmZOWba6TNIVDm+2UDaJmXSOXlasHKfNBs8oo3M0aT50fDEWfKZjXg==",
+ "dev": true,
+ "requires": {
+ "lodash": "^4.17.14"
+ }
+ },
+ "async-each": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/async-each/-/async-each-1.0.3.tgz",
+ "integrity": "sha512-z/WhQ5FPySLdvREByI2vZiTWwCnF0moMJ1hK9YQwDTHKh6I7/uSckMetoRGb5UBZPC1z0jlw+n/XCgjeH7y1AQ==",
+ "dev": true,
+ "optional": true
+ },
+ "atob": {
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/atob/-/atob-2.1.2.tgz",
+ "integrity": "sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==",
+ "dev": true
+ },
+ "balanced-match": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz",
+ "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=",
+ "dev": true
+ },
+ "base": {
+ "version": "0.11.2",
+ "resolved": "https://registry.npmjs.org/base/-/base-0.11.2.tgz",
+ "integrity": "sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg==",
+ "dev": true,
+ "requires": {
+ "cache-base": "^1.0.1",
+ "class-utils": "^0.3.5",
+ "component-emitter": "^1.2.1",
+ "define-property": "^1.0.0",
+ "isobject": "^3.0.1",
+ "mixin-deep": "^1.2.0",
+ "pascalcase": "^0.1.1"
+ },
+ "dependencies": {
+ "define-property": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz",
+ "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=",
+ "dev": true,
+ "requires": {
+ "is-descriptor": "^1.0.0"
+ }
+ },
+ "is-accessor-descriptor": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz",
+ "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==",
+ "dev": true,
+ "requires": {
+ "kind-of": "^6.0.0"
+ }
+ },
+ "is-data-descriptor": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz",
+ "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==",
+ "dev": true,
+ "requires": {
+ "kind-of": "^6.0.0"
+ }
+ },
+ "is-descriptor": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz",
+ "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==",
+ "dev": true,
+ "requires": {
+ "is-accessor-descriptor": "^1.0.0",
+ "is-data-descriptor": "^1.0.0",
+ "kind-of": "^6.0.2"
+ }
+ }
+ }
+ },
+ "base64-js": {
+ "version": "1.3.1",
+ "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.3.1.tgz",
+ "integrity": "sha512-mLQ4i2QO1ytvGWFWmcngKO//JXAQueZvwEKtjgQFM4jIK0kU+ytMfplL8j+n5mspOfjHwoAg+9yhb7BwAHm36g==",
+ "dev": true
+ },
+ "basic-auth": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/basic-auth/-/basic-auth-1.1.0.tgz",
+ "integrity": "sha1-RSIe5Cn37h5QNb4/UVM/HN/SmIQ=",
+ "dev": true
+ },
+ "big.js": {
+ "version": "5.2.2",
+ "resolved": "https://registry.npmjs.org/big.js/-/big.js-5.2.2.tgz",
+ "integrity": "sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==",
+ "dev": true
+ },
+ "binary-extensions": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.1.0.tgz",
+ "integrity": "sha512-1Yj8h9Q+QDF5FzhMs/c9+6UntbD5MkRfRwac8DoEm9ZfUBZ7tZ55YcGVAzEe4bXsdQHEk+s9S5wsOKVdZrw0tQ==",
+ "dev": true,
+ "optional": true
+ },
+ "bluebird": {
+ "version": "3.7.2",
+ "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz",
+ "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg=="
+ },
+ "bn.js": {
+ "version": "5.1.3",
+ "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.1.3.tgz",
+ "integrity": "sha512-GkTiFpjFtUzU9CbMeJ5iazkCzGL3jrhzerzZIuqLABjbwRaFt33I9tUdSNryIptM+RxDet6OKm2WnLXzW51KsQ==",
+ "dev": true
+ },
+ "brace-expansion": {
+ "version": "1.1.11",
+ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
+ "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
+ "dev": true,
+ "requires": {
+ "balanced-match": "^1.0.0",
+ "concat-map": "0.0.1"
+ }
+ },
+ "braces": {
+ "version": "2.3.2",
+ "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz",
+ "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==",
+ "dev": true,
+ "requires": {
+ "arr-flatten": "^1.1.0",
+ "array-unique": "^0.3.2",
+ "extend-shallow": "^2.0.1",
+ "fill-range": "^4.0.0",
+ "isobject": "^3.0.1",
+ "repeat-element": "^1.1.2",
+ "snapdragon": "^0.8.1",
+ "snapdragon-node": "^2.0.1",
+ "split-string": "^3.0.2",
+ "to-regex": "^3.0.1"
+ },
+ "dependencies": {
+ "extend-shallow": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
+ "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=",
+ "dev": true,
+ "requires": {
+ "is-extendable": "^0.1.0"
+ }
+ }
+ }
+ },
+ "brorand": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz",
+ "integrity": "sha1-EsJe/kCkXjwyPrhnWgoM5XsiNx8=",
+ "dev": true
+ },
+ "browserify-aes": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/browserify-aes/-/browserify-aes-1.2.0.tgz",
+ "integrity": "sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA==",
+ "dev": true,
+ "requires": {
+ "buffer-xor": "^1.0.3",
+ "cipher-base": "^1.0.0",
+ "create-hash": "^1.1.0",
+ "evp_bytestokey": "^1.0.3",
+ "inherits": "^2.0.1",
+ "safe-buffer": "^5.0.1"
+ }
+ },
+ "browserify-cipher": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/browserify-cipher/-/browserify-cipher-1.0.1.tgz",
+ "integrity": "sha512-sPhkz0ARKbf4rRQt2hTpAHqn47X3llLkUGn+xEJzLjwY8LRs2p0v7ljvI5EyoRO/mexrNunNECisZs+gw2zz1w==",
+ "dev": true,
+ "requires": {
+ "browserify-aes": "^1.0.4",
+ "browserify-des": "^1.0.0",
+ "evp_bytestokey": "^1.0.0"
+ }
+ },
+ "browserify-des": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/browserify-des/-/browserify-des-1.0.2.tgz",
+ "integrity": "sha512-BioO1xf3hFwz4kc6iBhI3ieDFompMhrMlnDFC4/0/vd5MokpuAc3R+LYbwTA9A5Yc9pq9UYPqffKpW2ObuwX5A==",
+ "dev": true,
+ "requires": {
+ "cipher-base": "^1.0.1",
+ "des.js": "^1.0.0",
+ "inherits": "^2.0.1",
+ "safe-buffer": "^5.1.2"
+ }
+ },
+ "browserify-rsa": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/browserify-rsa/-/browserify-rsa-4.0.1.tgz",
+ "integrity": "sha1-IeCr+vbyApzy+vsTNWenAdQTVSQ=",
+ "dev": true,
+ "requires": {
+ "bn.js": "^4.1.0",
+ "randombytes": "^2.0.1"
+ },
+ "dependencies": {
+ "bn.js": {
+ "version": "4.11.9",
+ "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.9.tgz",
+ "integrity": "sha512-E6QoYqCKZfgatHTdHzs1RRKP7ip4vvm+EyRUeE2RF0NblwVvb0p6jSVeNTOFxPn26QXN2o6SMfNxKp6kU8zQaw==",
+ "dev": true
+ }
+ }
+ },
+ "browserify-sign": {
+ "version": "4.2.1",
+ "resolved": "https://registry.npmjs.org/browserify-sign/-/browserify-sign-4.2.1.tgz",
+ "integrity": "sha512-/vrA5fguVAKKAVTNJjgSm1tRQDHUU6DbwO9IROu/0WAzC8PKhucDSh18J0RMvVeHAn5puMd+QHC2erPRNf8lmg==",
+ "dev": true,
+ "requires": {
+ "bn.js": "^5.1.1",
+ "browserify-rsa": "^4.0.1",
+ "create-hash": "^1.2.0",
+ "create-hmac": "^1.1.7",
+ "elliptic": "^6.5.3",
+ "inherits": "^2.0.4",
+ "parse-asn1": "^5.1.5",
+ "readable-stream": "^3.6.0",
+ "safe-buffer": "^5.2.0"
+ },
+ "dependencies": {
+ "readable-stream": {
+ "version": "3.6.0",
+ "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz",
+ "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==",
+ "dev": true,
+ "requires": {
+ "inherits": "^2.0.3",
+ "string_decoder": "^1.1.1",
+ "util-deprecate": "^1.0.1"
+ }
+ },
+ "safe-buffer": {
+ "version": "5.2.1",
+ "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
+ "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==",
+ "dev": true
+ }
+ }
+ },
+ "browserify-zlib": {
+ "version": "0.2.0",
+ "resolved": "https://registry.npmjs.org/browserify-zlib/-/browserify-zlib-0.2.0.tgz",
+ "integrity": "sha512-Z942RysHXmJrhqk88FmKBVq/v5tqmSkDz7p54G/MGyjMnCFFnC79XWNbg+Vta8W6Wb2qtSZTSxIGkJrRpCFEiA==",
+ "dev": true,
+ "requires": {
+ "pako": "~1.0.5"
+ }
+ },
+ "buffer": {
+ "version": "4.9.2",
+ "resolved": "https://registry.npmjs.org/buffer/-/buffer-4.9.2.tgz",
+ "integrity": "sha512-xq+q3SRMOxGivLhBNaUdC64hDTQwejJ+H0T/NB1XMtTVEwNTrfFF3gAxiyW0Bu/xWEGhjVKgUcMhCrUy2+uCWg==",
+ "dev": true,
+ "requires": {
+ "base64-js": "^1.0.2",
+ "ieee754": "^1.1.4",
+ "isarray": "^1.0.0"
+ }
+ },
+ "buffer-from": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz",
+ "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==",
+ "dev": true
+ },
+ "buffer-xor": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/buffer-xor/-/buffer-xor-1.0.3.tgz",
+ "integrity": "sha1-JuYe0UIvtw3ULm42cp7VHYVf6Nk=",
+ "dev": true
+ },
+ "builtin-status-codes": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/builtin-status-codes/-/builtin-status-codes-3.0.0.tgz",
+ "integrity": "sha1-hZgoeOIbmOHGZCXgPQF0eI9Wnug=",
+ "dev": true
+ },
+ "cacache": {
+ "version": "12.0.4",
+ "resolved": "https://registry.npmjs.org/cacache/-/cacache-12.0.4.tgz",
+ "integrity": "sha512-a0tMB40oefvuInr4Cwb3GerbL9xTj1D5yg0T5xrjGCGyfvbxseIXX7BAO/u/hIXdafzOI5JC3wDwHyf24buOAQ==",
+ "dev": true,
+ "requires": {
+ "bluebird": "^3.5.5",
+ "chownr": "^1.1.1",
+ "figgy-pudding": "^3.5.1",
+ "glob": "^7.1.4",
+ "graceful-fs": "^4.1.15",
+ "infer-owner": "^1.0.3",
+ "lru-cache": "^5.1.1",
+ "mississippi": "^3.0.0",
+ "mkdirp": "^0.5.1",
+ "move-concurrently": "^1.0.1",
+ "promise-inflight": "^1.0.1",
+ "rimraf": "^2.6.3",
+ "ssri": "^6.0.1",
+ "unique-filename": "^1.1.1",
+ "y18n": "^4.0.0"
+ }
+ },
+ "cache-base": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/cache-base/-/cache-base-1.0.1.tgz",
+ "integrity": "sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ==",
+ "dev": true,
+ "requires": {
+ "collection-visit": "^1.0.0",
+ "component-emitter": "^1.2.1",
+ "get-value": "^2.0.6",
+ "has-value": "^1.0.0",
+ "isobject": "^3.0.1",
+ "set-value": "^2.0.0",
+ "to-object-path": "^0.3.0",
+ "union-value": "^1.0.0",
+ "unset-value": "^1.0.0"
+ }
+ },
+ "camelcase": {
+ "version": "5.3.1",
+ "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz",
+ "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==",
+ "dev": true
+ },
+ "chalk": {
+ "version": "2.4.2",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
+ "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
+ "dev": true,
+ "requires": {
+ "ansi-styles": "^3.2.1",
+ "escape-string-regexp": "^1.0.5",
+ "supports-color": "^5.3.0"
+ },
+ "dependencies": {
+ "supports-color": {
+ "version": "5.5.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
+ "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
+ "dev": true,
+ "requires": {
+ "has-flag": "^3.0.0"
+ }
+ }
+ }
+ },
+ "chokidar": {
+ "version": "3.4.3",
+ "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.4.3.tgz",
+ "integrity": "sha512-DtM3g7juCXQxFVSNPNByEC2+NImtBuxQQvWlHunpJIS5Ocr0lG306cC7FCi7cEA0fzmybPUIl4txBIobk1gGOQ==",
+ "dev": true,
+ "optional": true,
+ "requires": {
+ "anymatch": "~3.1.1",
+ "braces": "~3.0.2",
+ "fsevents": "~2.1.2",
+ "glob-parent": "~5.1.0",
+ "is-binary-path": "~2.1.0",
+ "is-glob": "~4.0.1",
+ "normalize-path": "~3.0.0",
+ "readdirp": "~3.5.0"
+ },
+ "dependencies": {
+ "braces": {
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz",
+ "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==",
+ "dev": true,
+ "optional": true,
+ "requires": {
+ "fill-range": "^7.0.1"
+ }
+ },
+ "fill-range": {
+ "version": "7.0.1",
+ "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz",
+ "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==",
+ "dev": true,
+ "optional": true,
+ "requires": {
+ "to-regex-range": "^5.0.1"
+ }
+ },
+ "is-number": {
+ "version": "7.0.0",
+ "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
+ "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
+ "dev": true,
+ "optional": true
+ },
+ "to-regex-range": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
+ "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
+ "dev": true,
+ "optional": true,
+ "requires": {
+ "is-number": "^7.0.0"
+ }
+ }
+ }
+ },
+ "chownr": {
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz",
+ "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==",
+ "dev": true
+ },
+ "chrome-trace-event": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.2.tgz",
+ "integrity": "sha512-9e/zx1jw7B4CO+c/RXoCsfg/x1AfUBioy4owYH0bJprEYAx5hRFLRhWBqHAG57D0ZM4H7vxbP7bPe0VwhQRYDQ==",
+ "dev": true,
+ "requires": {
+ "tslib": "^1.9.0"
+ }
+ },
+ "cipher-base": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/cipher-base/-/cipher-base-1.0.4.tgz",
+ "integrity": "sha512-Kkht5ye6ZGmwv40uUDZztayT2ThLQGfnj/T71N/XzeZeo3nf8foyW7zGTsPYkEya3m5f3cAypH+qe7YOrM1U2Q==",
+ "dev": true,
+ "requires": {
+ "inherits": "^2.0.1",
+ "safe-buffer": "^5.0.1"
+ }
+ },
+ "class-utils": {
+ "version": "0.3.6",
+ "resolved": "https://registry.npmjs.org/class-utils/-/class-utils-0.3.6.tgz",
+ "integrity": "sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg==",
+ "dev": true,
+ "requires": {
+ "arr-union": "^3.1.0",
+ "define-property": "^0.2.5",
+ "isobject": "^3.0.0",
+ "static-extend": "^0.1.1"
+ },
+ "dependencies": {
+ "define-property": {
+ "version": "0.2.5",
+ "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz",
+ "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=",
+ "dev": true,
+ "requires": {
+ "is-descriptor": "^0.1.0"
+ }
+ }
+ }
+ },
+ "clean-stack": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz",
+ "integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==",
+ "dev": true
+ },
+ "cliui": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/cliui/-/cliui-5.0.0.tgz",
+ "integrity": "sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA==",
+ "dev": true,
+ "requires": {
+ "string-width": "^3.1.0",
+ "strip-ansi": "^5.2.0",
+ "wrap-ansi": "^5.1.0"
+ }
+ },
+ "collection-visit": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/collection-visit/-/collection-visit-1.0.0.tgz",
+ "integrity": "sha1-S8A3PBZLwykbTTaMgpzxqApZ3KA=",
+ "dev": true,
+ "requires": {
+ "map-visit": "^1.0.0",
+ "object-visit": "^1.0.0"
+ }
+ },
+ "color-convert": {
+ "version": "1.9.3",
+ "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
+ "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==",
+ "dev": true,
+ "requires": {
+ "color-name": "1.1.3"
+ }
+ },
+ "color-name": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
+ "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=",
+ "dev": true
+ },
+ "colors": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/colors/-/colors-1.4.0.tgz",
+ "integrity": "sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA==",
+ "dev": true
+ },
+ "commander": {
+ "version": "2.20.3",
+ "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz",
+ "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==",
+ "dev": true
+ },
+ "commondir": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz",
+ "integrity": "sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs=",
+ "dev": true
+ },
+ "component-emitter": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.0.tgz",
+ "integrity": "sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg==",
+ "dev": true
+ },
+ "concat-map": {
+ "version": "0.0.1",
+ "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
+ "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=",
+ "dev": true
+ },
+ "concat-stream": {
+ "version": "1.6.2",
+ "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz",
+ "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==",
+ "dev": true,
+ "requires": {
+ "buffer-from": "^1.0.0",
+ "inherits": "^2.0.3",
+ "readable-stream": "^2.2.2",
+ "typedarray": "^0.0.6"
+ }
+ },
+ "console-browserify": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/console-browserify/-/console-browserify-1.2.0.tgz",
+ "integrity": "sha512-ZMkYO/LkF17QvCPqM0gxw8yUzigAOZOSWSHg91FH6orS7vcEj5dVZTidN2fQ14yBSdg97RqhSNwLUXInd52OTA==",
+ "dev": true
+ },
+ "constants-browserify": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/constants-browserify/-/constants-browserify-1.0.0.tgz",
+ "integrity": "sha1-wguW2MYXdIqvHBYCF2DNJ/y4y3U=",
+ "dev": true
+ },
+ "copy-concurrently": {
+ "version": "1.0.5",
+ "resolved": "https://registry.npmjs.org/copy-concurrently/-/copy-concurrently-1.0.5.tgz",
+ "integrity": "sha512-f2domd9fsVDFtaFcbaRZuYXwtdmnzqbADSwhSWYxYB/Q8zsdUUFMXVRwXGDMWmbEzAn1kdRrtI1T/KTFOL4X2A==",
+ "dev": true,
+ "requires": {
+ "aproba": "^1.1.1",
+ "fs-write-stream-atomic": "^1.0.8",
+ "iferr": "^0.1.5",
+ "mkdirp": "^0.5.1",
+ "rimraf": "^2.5.4",
+ "run-queue": "^1.0.0"
+ }
+ },
+ "copy-descriptor": {
+ "version": "0.1.1",
+ "resolved": "https://registry.npmjs.org/copy-descriptor/-/copy-descriptor-0.1.1.tgz",
+ "integrity": "sha1-Z29us8OZl8LuGsOpJP1hJHSPV40=",
+ "dev": true
+ },
+ "copy-webpack-plugin": {
+ "version": "6.2.1",
+ "resolved": "https://registry.npmjs.org/copy-webpack-plugin/-/copy-webpack-plugin-6.2.1.tgz",
+ "integrity": "sha512-VH2ZTMIBsx4p++Lmpg77adZ0KUyM5gFR/9cuTrbneNnJlcQXUFvsNariPqq2dq2kV3F2skHiDGPQCyKWy1+U0Q==",
+ "dev": true,
+ "requires": {
+ "cacache": "^15.0.5",
+ "fast-glob": "^3.2.4",
+ "find-cache-dir": "^3.3.1",
+ "glob-parent": "^5.1.1",
+ "globby": "^11.0.1",
+ "loader-utils": "^2.0.0",
+ "normalize-path": "^3.0.0",
+ "p-limit": "^3.0.2",
+ "schema-utils": "^3.0.0",
+ "serialize-javascript": "^5.0.1",
+ "webpack-sources": "^1.4.3"
+ },
+ "dependencies": {
+ "cacache": {
+ "version": "15.0.5",
+ "resolved": "https://registry.npmjs.org/cacache/-/cacache-15.0.5.tgz",
+ "integrity": "sha512-lloiL22n7sOjEEXdL8NAjTgv9a1u43xICE9/203qonkZUCj5X1UEWIdf2/Y0d6QcCtMzbKQyhrcDbdvlZTs/+A==",
+ "dev": true,
+ "requires": {
+ "@npmcli/move-file": "^1.0.1",
+ "chownr": "^2.0.0",
+ "fs-minipass": "^2.0.0",
+ "glob": "^7.1.4",
+ "infer-owner": "^1.0.4",
+ "lru-cache": "^6.0.0",
+ "minipass": "^3.1.1",
+ "minipass-collect": "^1.0.2",
+ "minipass-flush": "^1.0.5",
+ "minipass-pipeline": "^1.2.2",
+ "mkdirp": "^1.0.3",
+ "p-map": "^4.0.0",
+ "promise-inflight": "^1.0.1",
+ "rimraf": "^3.0.2",
+ "ssri": "^8.0.0",
+ "tar": "^6.0.2",
+ "unique-filename": "^1.1.1"
+ }
+ },
+ "chownr": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz",
+ "integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==",
+ "dev": true
+ },
+ "find-cache-dir": {
+ "version": "3.3.1",
+ "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-3.3.1.tgz",
+ "integrity": "sha512-t2GDMt3oGC/v+BMwzmllWDuJF/xcDtE5j/fCGbqDD7OLuJkj0cfh1YSA5VKPvwMeLFLNDBkwOKZ2X85jGLVftQ==",
+ "dev": true,
+ "requires": {
+ "commondir": "^1.0.1",
+ "make-dir": "^3.0.2",
+ "pkg-dir": "^4.1.0"
+ }
+ },
+ "find-up": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz",
+ "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==",
+ "dev": true,
+ "requires": {
+ "locate-path": "^5.0.0",
+ "path-exists": "^4.0.0"
+ }
+ },
+ "json5": {
+ "version": "2.1.3",
+ "resolved": "https://registry.npmjs.org/json5/-/json5-2.1.3.tgz",
+ "integrity": "sha512-KXPvOm8K9IJKFM0bmdn8QXh7udDh1g/giieX0NLCaMnb4hEiVFqnop2ImTXCc5e0/oHz3LTqmHGtExn5hfMkOA==",
+ "dev": true,
+ "requires": {
+ "minimist": "^1.2.5"
+ }
+ },
+ "loader-utils": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.0.tgz",
+ "integrity": "sha512-rP4F0h2RaWSvPEkD7BLDFQnvSf+nK+wr3ESUjNTyAGobqrijmW92zc+SO6d4p4B1wh7+B/Jg1mkQe5NYUEHtHQ==",
+ "dev": true,
+ "requires": {
+ "big.js": "^5.2.2",
+ "emojis-list": "^3.0.0",
+ "json5": "^2.1.2"
+ }
+ },
+ "locate-path": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz",
+ "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==",
+ "dev": true,
+ "requires": {
+ "p-locate": "^4.1.0"
+ }
+ },
+ "lru-cache": {
+ "version": "6.0.0",
+ "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
+ "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
+ "dev": true,
+ "requires": {
+ "yallist": "^4.0.0"
+ }
+ },
+ "make-dir": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz",
+ "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==",
+ "dev": true,
+ "requires": {
+ "semver": "^6.0.0"
+ }
+ },
+ "mkdirp": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz",
+ "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==",
+ "dev": true
+ },
+ "p-limit": {
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.0.2.tgz",
+ "integrity": "sha512-iwqZSOoWIW+Ew4kAGUlN16J4M7OB3ysMLSZtnhmqx7njIHFPlxWBX8xo3lVTyFVq6mI/lL9qt2IsN1sHwaxJkg==",
+ "dev": true,
+ "requires": {
+ "p-try": "^2.0.0"
+ }
+ },
+ "p-locate": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz",
+ "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==",
+ "dev": true,
+ "requires": {
+ "p-limit": "^2.2.0"
+ },
+ "dependencies": {
+ "p-limit": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz",
+ "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==",
+ "dev": true,
+ "requires": {
+ "p-try": "^2.0.0"
+ }
+ }
+ }
+ },
+ "path-exists": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz",
+ "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==",
+ "dev": true
+ },
+ "pkg-dir": {
+ "version": "4.2.0",
+ "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz",
+ "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==",
+ "dev": true,
+ "requires": {
+ "find-up": "^4.0.0"
+ }
+ },
+ "rimraf": {
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz",
+ "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==",
+ "dev": true,
+ "requires": {
+ "glob": "^7.1.3"
+ }
+ },
+ "schema-utils": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.0.0.tgz",
+ "integrity": "sha512-6D82/xSzO094ajanoOSbe4YvXWMfn2A//8Y1+MUqFAJul5Bs+yn36xbK9OtNDcRVSBJ9jjeoXftM6CfztsjOAA==",
+ "dev": true,
+ "requires": {
+ "@types/json-schema": "^7.0.6",
+ "ajv": "^6.12.5",
+ "ajv-keywords": "^3.5.2"
+ }
+ },
+ "semver": {
+ "version": "6.3.0",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
+ "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
+ "dev": true
+ },
+ "serialize-javascript": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-5.0.1.tgz",
+ "integrity": "sha512-SaaNal9imEO737H2c05Og0/8LUXG7EnsZyMa8MzkmuHoELfT6txuj0cMqRj6zfPKnmQ1yasR4PCJc8x+M4JSPA==",
+ "dev": true,
+ "requires": {
+ "randombytes": "^2.1.0"
+ }
+ },
+ "ssri": {
+ "version": "8.0.0",
+ "resolved": "https://registry.npmjs.org/ssri/-/ssri-8.0.0.tgz",
+ "integrity": "sha512-aq/pz989nxVYwn16Tsbj1TqFpD5LLrQxHf5zaHuieFV+R0Bbr4y8qUsOA45hXT/N4/9UNXTarBjnjVmjSOVaAA==",
+ "dev": true,
+ "requires": {
+ "minipass": "^3.1.1"
+ }
+ },
+ "yallist": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
+ "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==",
+ "dev": true
+ }
+ }
+ },
+ "core-util-is": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz",
+ "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=",
+ "dev": true
+ },
+ "corser": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/corser/-/corser-2.0.1.tgz",
+ "integrity": "sha1-jtolLsqrWEDc2XXOuQ2TcMgZ/4c=",
+ "dev": true
+ },
+ "create-ecdh": {
+ "version": "4.0.4",
+ "resolved": "https://registry.npmjs.org/create-ecdh/-/create-ecdh-4.0.4.tgz",
+ "integrity": "sha512-mf+TCx8wWc9VpuxfP2ht0iSISLZnt0JgWlrOKZiNqyUZWnjIaCIVNQArMHnCZKfEYRg6IM7A+NeJoN8gf/Ws0A==",
+ "dev": true,
+ "requires": {
+ "bn.js": "^4.1.0",
+ "elliptic": "^6.5.3"
+ },
+ "dependencies": {
+ "bn.js": {
+ "version": "4.11.9",
+ "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.9.tgz",
+ "integrity": "sha512-E6QoYqCKZfgatHTdHzs1RRKP7ip4vvm+EyRUeE2RF0NblwVvb0p6jSVeNTOFxPn26QXN2o6SMfNxKp6kU8zQaw==",
+ "dev": true
+ }
+ }
+ },
+ "create-hash": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/create-hash/-/create-hash-1.2.0.tgz",
+ "integrity": "sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg==",
+ "dev": true,
+ "requires": {
+ "cipher-base": "^1.0.1",
+ "inherits": "^2.0.1",
+ "md5.js": "^1.3.4",
+ "ripemd160": "^2.0.1",
+ "sha.js": "^2.4.0"
+ }
+ },
+ "create-hmac": {
+ "version": "1.1.7",
+ "resolved": "https://registry.npmjs.org/create-hmac/-/create-hmac-1.1.7.tgz",
+ "integrity": "sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg==",
+ "dev": true,
+ "requires": {
+ "cipher-base": "^1.0.3",
+ "create-hash": "^1.1.0",
+ "inherits": "^2.0.1",
+ "ripemd160": "^2.0.0",
+ "safe-buffer": "^5.0.1",
+ "sha.js": "^2.4.8"
+ }
+ },
+ "cross-spawn": {
+ "version": "6.0.5",
+ "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz",
+ "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==",
+ "dev": true,
+ "requires": {
+ "nice-try": "^1.0.4",
+ "path-key": "^2.0.1",
+ "semver": "^5.5.0",
+ "shebang-command": "^1.2.0",
+ "which": "^1.2.9"
+ }
+ },
+ "crypto-browserify": {
+ "version": "3.12.0",
+ "resolved": "https://registry.npmjs.org/crypto-browserify/-/crypto-browserify-3.12.0.tgz",
+ "integrity": "sha512-fz4spIh+znjO2VjL+IdhEpRJ3YN6sMzITSBijk6FK2UvTqruSQW+/cCZTSNsMiZNvUeq0CqurF+dAbyiGOY6Wg==",
+ "dev": true,
+ "requires": {
+ "browserify-cipher": "^1.0.0",
+ "browserify-sign": "^4.0.0",
+ "create-ecdh": "^4.0.0",
+ "create-hash": "^1.1.0",
+ "create-hmac": "^1.1.0",
+ "diffie-hellman": "^5.0.0",
+ "inherits": "^2.0.1",
+ "pbkdf2": "^3.0.3",
+ "public-encrypt": "^4.0.0",
+ "randombytes": "^2.0.0",
+ "randomfill": "^1.0.3"
+ }
+ },
+ "cyclist": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/cyclist/-/cyclist-1.0.1.tgz",
+ "integrity": "sha1-WW6WmP0MgOEgOMK4LW6xs1tiJNk=",
+ "dev": true
+ },
+ "debug": {
+ "version": "2.6.9",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
+ "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
+ "dev": true,
+ "requires": {
+ "ms": "2.0.0"
+ }
+ },
+ "decamelize": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz",
+ "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=",
+ "dev": true
+ },
+ "decode-uri-component": {
+ "version": "0.2.0",
+ "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.0.tgz",
+ "integrity": "sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU=",
+ "dev": true
+ },
+ "define-property": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz",
+ "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==",
+ "dev": true,
+ "requires": {
+ "is-descriptor": "^1.0.2",
+ "isobject": "^3.0.1"
+ },
+ "dependencies": {
+ "is-accessor-descriptor": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz",
+ "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==",
+ "dev": true,
+ "requires": {
+ "kind-of": "^6.0.0"
+ }
+ },
+ "is-data-descriptor": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz",
+ "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==",
+ "dev": true,
+ "requires": {
+ "kind-of": "^6.0.0"
+ }
+ },
+ "is-descriptor": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz",
+ "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==",
+ "dev": true,
+ "requires": {
+ "is-accessor-descriptor": "^1.0.0",
+ "is-data-descriptor": "^1.0.0",
+ "kind-of": "^6.0.2"
+ }
+ }
+ }
+ },
+ "des.js": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/des.js/-/des.js-1.0.1.tgz",
+ "integrity": "sha512-Q0I4pfFrv2VPd34/vfLrFOoRmlYj3OV50i7fskps1jZWK1kApMWWT9G6RRUeYedLcBDIhnSDaUvJMb3AhUlaEA==",
+ "dev": true,
+ "requires": {
+ "inherits": "^2.0.1",
+ "minimalistic-assert": "^1.0.0"
+ }
+ },
+ "detect-file": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/detect-file/-/detect-file-1.0.0.tgz",
+ "integrity": "sha1-8NZtA2cqglyxtzvbP+YjEMjlUrc=",
+ "dev": true
+ },
+ "diffie-hellman": {
+ "version": "5.0.3",
+ "resolved": "https://registry.npmjs.org/diffie-hellman/-/diffie-hellman-5.0.3.tgz",
+ "integrity": "sha512-kqag/Nl+f3GwyK25fhUMYj81BUOrZ9IuJsjIcDE5icNM9FJHAVm3VcUDxdLPoQtTuUylWm6ZIknYJwwaPxsUzg==",
+ "dev": true,
+ "requires": {
+ "bn.js": "^4.1.0",
+ "miller-rabin": "^4.0.0",
+ "randombytes": "^2.0.0"
+ },
+ "dependencies": {
+ "bn.js": {
+ "version": "4.11.9",
+ "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.9.tgz",
+ "integrity": "sha512-E6QoYqCKZfgatHTdHzs1RRKP7ip4vvm+EyRUeE2RF0NblwVvb0p6jSVeNTOFxPn26QXN2o6SMfNxKp6kU8zQaw==",
+ "dev": true
+ }
+ }
+ },
+ "dir-glob": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz",
+ "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==",
+ "dev": true,
+ "requires": {
+ "path-type": "^4.0.0"
+ }
+ },
+ "domain-browser": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/domain-browser/-/domain-browser-1.2.0.tgz",
+ "integrity": "sha512-jnjyiM6eRyZl2H+W8Q/zLMA481hzi0eszAaBUzIVnmYVDBbnLxVNnfu1HgEBvCbL+71FrxMl3E6lpKH7Ge3OXA==",
+ "dev": true
+ },
+ "duplexify": {
+ "version": "3.7.1",
+ "resolved": "https://registry.npmjs.org/duplexify/-/duplexify-3.7.1.tgz",
+ "integrity": "sha512-07z8uv2wMyS51kKhD1KsdXJg5WQ6t93RneqRxUHnskXVtlYYkLqM0gqStQZ3pj073g687jPCHrqNfCzawLYh5g==",
+ "dev": true,
+ "requires": {
+ "end-of-stream": "^1.0.0",
+ "inherits": "^2.0.1",
+ "readable-stream": "^2.0.0",
+ "stream-shift": "^1.0.0"
+ }
+ },
+ "ecstatic": {
+ "version": "3.3.2",
+ "resolved": "https://registry.npmjs.org/ecstatic/-/ecstatic-3.3.2.tgz",
+ "integrity": "sha512-fLf9l1hnwrHI2xn9mEDT7KIi22UDqA2jaCwyCbSUJh9a1V+LEUSL/JO/6TIz/QyuBURWUHrFL5Kg2TtO1bkkog==",
+ "dev": true,
+ "requires": {
+ "he": "^1.1.1",
+ "mime": "^1.6.0",
+ "minimist": "^1.1.0",
+ "url-join": "^2.0.5"
+ }
+ },
+ "elliptic": {
+ "version": "6.5.3",
+ "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.5.3.tgz",
+ "integrity": "sha512-IMqzv5wNQf+E6aHeIqATs0tOLeOTwj1QKbRcS3jBbYkl5oLAserA8yJTT7/VyHUYG91PRmPyeQDObKLPpeS4dw==",
+ "dev": true,
+ "requires": {
+ "bn.js": "^4.4.0",
+ "brorand": "^1.0.1",
+ "hash.js": "^1.0.0",
+ "hmac-drbg": "^1.0.0",
+ "inherits": "^2.0.1",
+ "minimalistic-assert": "^1.0.0",
+ "minimalistic-crypto-utils": "^1.0.0"
+ },
+ "dependencies": {
+ "bn.js": {
+ "version": "4.11.9",
+ "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.9.tgz",
+ "integrity": "sha512-E6QoYqCKZfgatHTdHzs1RRKP7ip4vvm+EyRUeE2RF0NblwVvb0p6jSVeNTOFxPn26QXN2o6SMfNxKp6kU8zQaw==",
+ "dev": true
+ }
+ }
+ },
+ "emoji-regex": {
+ "version": "7.0.3",
+ "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz",
+ "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==",
+ "dev": true
+ },
+ "emojis-list": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-3.0.0.tgz",
+ "integrity": "sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q==",
+ "dev": true
+ },
+ "end-of-stream": {
+ "version": "1.4.4",
+ "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz",
+ "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==",
+ "dev": true,
+ "requires": {
+ "once": "^1.4.0"
+ }
+ },
+ "enhanced-resolve": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-4.3.0.tgz",
+ "integrity": "sha512-3e87LvavsdxyoCfGusJnrZ5G8SLPOFeHSNpZI/ATL9a5leXo2k0w6MKnbqhdBad9qTobSfB20Ld7UmgoNbAZkQ==",
+ "dev": true,
+ "requires": {
+ "graceful-fs": "^4.1.2",
+ "memory-fs": "^0.5.0",
+ "tapable": "^1.0.0"
+ },
+ "dependencies": {
+ "memory-fs": {
+ "version": "0.5.0",
+ "resolved": "https://registry.npmjs.org/memory-fs/-/memory-fs-0.5.0.tgz",
+ "integrity": "sha512-jA0rdU5KoQMC0e6ppoNRtpp6vjFq6+NY7r8hywnC7V+1Xj/MtHwGIbB1QaK/dunyjWteJzmkpd7ooeWg10T7GA==",
+ "dev": true,
+ "requires": {
+ "errno": "^0.1.3",
+ "readable-stream": "^2.0.1"
+ }
+ }
+ }
+ },
+ "errno": {
+ "version": "0.1.7",
+ "resolved": "https://registry.npmjs.org/errno/-/errno-0.1.7.tgz",
+ "integrity": "sha512-MfrRBDWzIWifgq6tJj60gkAwtLNb6sQPlcFrSOflcP1aFmmruKQ2wRnze/8V6kgyz7H3FF8Npzv78mZ7XLLflg==",
+ "dev": true,
+ "requires": {
+ "prr": "~1.0.1"
+ }
+ },
+ "escape-string-regexp": {
+ "version": "1.0.5",
+ "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
+ "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=",
+ "dev": true
+ },
+ "eslint-scope": {
+ "version": "4.0.3",
+ "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-4.0.3.tgz",
+ "integrity": "sha512-p7VutNr1O/QrxysMo3E45FjYDTeXBy0iTltPFNSqKAIfjDSXC+4dj+qfyuD8bfAXrW/y6lW3O76VaYNPKfpKrg==",
+ "dev": true,
+ "requires": {
+ "esrecurse": "^4.1.0",
+ "estraverse": "^4.1.1"
+ }
+ },
+ "esrecurse": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz",
+ "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==",
+ "dev": true,
+ "requires": {
+ "estraverse": "^5.2.0"
+ },
+ "dependencies": {
+ "estraverse": {
+ "version": "5.2.0",
+ "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz",
+ "integrity": "sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==",
+ "dev": true
+ }
+ }
+ },
+ "estraverse": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz",
+ "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==",
+ "dev": true
+ },
+ "eventemitter3": {
+ "version": "4.0.4",
+ "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.4.tgz",
+ "integrity": "sha512-rlaVLnVxtxvoyLsQQFBx53YmXHDxRIzzTLbdfxqi4yocpSjAxXwkU0cScM5JgSKMqEhrZpnvQ2D9gjylR0AimQ==",
+ "dev": true
+ },
+ "events": {
+ "version": "3.2.0",
+ "resolved": "https://registry.npmjs.org/events/-/events-3.2.0.tgz",
+ "integrity": "sha512-/46HWwbfCX2xTawVfkKLGxMifJYQBWMwY1mjywRtb4c9x8l5NP3KoJtnIOiL1hfdRkIuYhETxQlo62IF8tcnlg==",
+ "dev": true
+ },
+ "evp_bytestokey": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz",
+ "integrity": "sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA==",
+ "dev": true,
+ "requires": {
+ "md5.js": "^1.3.4",
+ "safe-buffer": "^5.1.1"
+ }
+ },
+ "expand-brackets": {
+ "version": "2.1.4",
+ "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz",
+ "integrity": "sha1-t3c14xXOMPa27/D4OwQVGiJEliI=",
+ "dev": true,
+ "requires": {
+ "debug": "^2.3.3",
+ "define-property": "^0.2.5",
+ "extend-shallow": "^2.0.1",
+ "posix-character-classes": "^0.1.0",
+ "regex-not": "^1.0.0",
+ "snapdragon": "^0.8.1",
+ "to-regex": "^3.0.1"
+ },
+ "dependencies": {
+ "define-property": {
+ "version": "0.2.5",
+ "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz",
+ "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=",
+ "dev": true,
+ "requires": {
+ "is-descriptor": "^0.1.0"
+ }
+ },
+ "extend-shallow": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
+ "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=",
+ "dev": true,
+ "requires": {
+ "is-extendable": "^0.1.0"
+ }
+ }
+ }
+ },
+ "expand-tilde": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/expand-tilde/-/expand-tilde-2.0.2.tgz",
+ "integrity": "sha1-l+gBqgUt8CRU3kawK/YhZCzchQI=",
+ "dev": true,
+ "requires": {
+ "homedir-polyfill": "^1.0.1"
+ }
+ },
+ "extend-shallow": {
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz",
+ "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=",
+ "dev": true,
+ "requires": {
+ "assign-symbols": "^1.0.0",
+ "is-extendable": "^1.0.1"
+ },
+ "dependencies": {
+ "is-extendable": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz",
+ "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==",
+ "dev": true,
+ "requires": {
+ "is-plain-object": "^2.0.4"
+ }
+ }
+ }
+ },
+ "extglob": {
+ "version": "2.0.4",
+ "resolved": "https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz",
+ "integrity": "sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==",
+ "dev": true,
+ "requires": {
+ "array-unique": "^0.3.2",
+ "define-property": "^1.0.0",
+ "expand-brackets": "^2.1.4",
+ "extend-shallow": "^2.0.1",
+ "fragment-cache": "^0.2.1",
+ "regex-not": "^1.0.0",
+ "snapdragon": "^0.8.1",
+ "to-regex": "^3.0.1"
+ },
+ "dependencies": {
+ "define-property": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz",
+ "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=",
+ "dev": true,
+ "requires": {
+ "is-descriptor": "^1.0.0"
+ }
+ },
+ "extend-shallow": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
+ "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=",
+ "dev": true,
+ "requires": {
+ "is-extendable": "^0.1.0"
+ }
+ },
+ "is-accessor-descriptor": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz",
+ "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==",
+ "dev": true,
+ "requires": {
+ "kind-of": "^6.0.0"
+ }
+ },
+ "is-data-descriptor": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz",
+ "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==",
+ "dev": true,
+ "requires": {
+ "kind-of": "^6.0.0"
+ }
+ },
+ "is-descriptor": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz",
+ "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==",
+ "dev": true,
+ "requires": {
+ "is-accessor-descriptor": "^1.0.0",
+ "is-data-descriptor": "^1.0.0",
+ "kind-of": "^6.0.2"
+ }
+ }
+ }
+ },
+ "fast-deep-equal": {
+ "version": "3.1.3",
+ "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
+ "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==",
+ "dev": true
+ },
+ "fast-glob": {
+ "version": "3.2.4",
+ "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.4.tgz",
+ "integrity": "sha512-kr/Oo6PX51265qeuCYsyGypiO5uJFgBS0jksyG7FUeCyQzNwYnzrNIMR1NXfkZXsMYXYLRAHgISHBz8gQcxKHQ==",
+ "dev": true,
+ "requires": {
+ "@nodelib/fs.stat": "^2.0.2",
+ "@nodelib/fs.walk": "^1.2.3",
+ "glob-parent": "^5.1.0",
+ "merge2": "^1.3.0",
+ "micromatch": "^4.0.2",
+ "picomatch": "^2.2.1"
+ },
+ "dependencies": {
+ "braces": {
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz",
+ "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==",
+ "dev": true,
+ "requires": {
+ "fill-range": "^7.0.1"
+ }
+ },
+ "fill-range": {
+ "version": "7.0.1",
+ "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz",
+ "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==",
+ "dev": true,
+ "requires": {
+ "to-regex-range": "^5.0.1"
+ }
+ },
+ "is-number": {
+ "version": "7.0.0",
+ "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
+ "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
+ "dev": true
+ },
+ "micromatch": {
+ "version": "4.0.2",
+ "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.2.tgz",
+ "integrity": "sha512-y7FpHSbMUMoyPbYUSzO6PaZ6FyRnQOpHuKwbo1G+Knck95XVU4QAiKdGEnj5wwoS7PlOgthX/09u5iFJ+aYf5Q==",
+ "dev": true,
+ "requires": {
+ "braces": "^3.0.1",
+ "picomatch": "^2.0.5"
+ }
+ },
+ "to-regex-range": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
+ "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
+ "dev": true,
+ "requires": {
+ "is-number": "^7.0.0"
+ }
+ }
+ }
+ },
+ "fast-json-stable-stringify": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz",
+ "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==",
+ "dev": true
+ },
+ "fastq": {
+ "version": "1.8.0",
+ "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.8.0.tgz",
+ "integrity": "sha512-SMIZoZdLh/fgofivvIkmknUXyPnvxRE3DhtZ5Me3Mrsk5gyPL42F0xr51TdRXskBxHfMp+07bcYzfsYEsSQA9Q==",
+ "dev": true,
+ "requires": {
+ "reusify": "^1.0.4"
+ }
+ },
+ "figgy-pudding": {
+ "version": "3.5.2",
+ "resolved": "https://registry.npmjs.org/figgy-pudding/-/figgy-pudding-3.5.2.tgz",
+ "integrity": "sha512-0btnI/H8f2pavGMN8w40mlSKOfTK2SVJmBfBeVIj3kNw0swwgzyRq0d5TJVOwodFmtvpPeWPN/MCcfuWF0Ezbw==",
+ "dev": true
+ },
+ "fill-range": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz",
+ "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=",
+ "dev": true,
+ "requires": {
+ "extend-shallow": "^2.0.1",
+ "is-number": "^3.0.0",
+ "repeat-string": "^1.6.1",
+ "to-regex-range": "^2.1.0"
+ },
+ "dependencies": {
+ "extend-shallow": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
+ "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=",
+ "dev": true,
+ "requires": {
+ "is-extendable": "^0.1.0"
+ }
+ }
+ }
+ },
+ "find-cache-dir": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-2.1.0.tgz",
+ "integrity": "sha512-Tq6PixE0w/VMFfCgbONnkiQIVol/JJL7nRMi20fqzA4NRs9AfeqMGeRdPi3wIhYkxjeBaWh2rxwapn5Tu3IqOQ==",
+ "dev": true,
+ "requires": {
+ "commondir": "^1.0.1",
+ "make-dir": "^2.0.0",
+ "pkg-dir": "^3.0.0"
+ }
+ },
+ "find-up": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz",
+ "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==",
+ "dev": true,
+ "requires": {
+ "locate-path": "^3.0.0"
+ }
+ },
+ "findup-sync": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/findup-sync/-/findup-sync-3.0.0.tgz",
+ "integrity": "sha512-YbffarhcicEhOrm4CtrwdKBdCuz576RLdhJDsIfvNtxUuhdRet1qZcsMjqbePtAseKdAnDyM/IyXbu7PRPRLYg==",
+ "dev": true,
+ "requires": {
+ "detect-file": "^1.0.0",
+ "is-glob": "^4.0.0",
+ "micromatch": "^3.0.4",
+ "resolve-dir": "^1.0.1"
+ }
+ },
+ "flush-write-stream": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/flush-write-stream/-/flush-write-stream-1.1.1.tgz",
+ "integrity": "sha512-3Z4XhFZ3992uIq0XOqb9AreonueSYphE6oYbpt5+3u06JWklbsPkNv3ZKkP9Bz/r+1MWCaMoSQ28P85+1Yc77w==",
+ "dev": true,
+ "requires": {
+ "inherits": "^2.0.3",
+ "readable-stream": "^2.3.6"
+ }
+ },
+ "follow-redirects": {
+ "version": "1.12.1",
+ "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.12.1.tgz",
+ "integrity": "sha512-tmRv0AVuR7ZyouUHLeNSiO6pqulF7dYa3s19c6t+wz9LD69/uSzdMxJ2S91nTI9U3rt/IldxpzMOFejp6f0hjg==",
+ "dev": true
+ },
+ "for-in": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz",
+ "integrity": "sha1-gQaNKVqBQuwKxybG4iAMMPttXoA=",
+ "dev": true
+ },
+ "fragment-cache": {
+ "version": "0.2.1",
+ "resolved": "https://registry.npmjs.org/fragment-cache/-/fragment-cache-0.2.1.tgz",
+ "integrity": "sha1-QpD60n8T6Jvn8zeZxrxaCr//DRk=",
+ "dev": true,
+ "requires": {
+ "map-cache": "^0.2.2"
+ }
+ },
+ "from2": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/from2/-/from2-2.3.0.tgz",
+ "integrity": "sha1-i/tVAr3kpNNs/e6gB/zKIdfjgq8=",
+ "dev": true,
+ "requires": {
+ "inherits": "^2.0.1",
+ "readable-stream": "^2.0.0"
+ }
+ },
+ "fs-minipass": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz",
+ "integrity": "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==",
+ "dev": true,
+ "requires": {
+ "minipass": "^3.0.0"
+ }
+ },
+ "fs-write-stream-atomic": {
+ "version": "1.0.10",
+ "resolved": "https://registry.npmjs.org/fs-write-stream-atomic/-/fs-write-stream-atomic-1.0.10.tgz",
+ "integrity": "sha1-tH31NJPvkR33VzHnCp3tAYnbQMk=",
+ "dev": true,
+ "requires": {
+ "graceful-fs": "^4.1.2",
+ "iferr": "^0.1.5",
+ "imurmurhash": "^0.1.4",
+ "readable-stream": "1 || 2"
+ }
+ },
+ "fs.realpath": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
+ "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=",
+ "dev": true
+ },
+ "fsevents": {
+ "version": "2.1.3",
+ "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.1.3.tgz",
+ "integrity": "sha512-Auw9a4AxqWpa9GUfj370BMPzzyncfBABW8Mab7BGWBYDj4Isgq+cDKtx0i6u9jcX9pQDnswsaaOTgTmA5pEjuQ==",
+ "dev": true,
+ "optional": true
+ },
+ "get-caller-file": {
+ "version": "2.0.5",
+ "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz",
+ "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==",
+ "dev": true
+ },
+ "get-value": {
+ "version": "2.0.6",
+ "resolved": "https://registry.npmjs.org/get-value/-/get-value-2.0.6.tgz",
+ "integrity": "sha1-3BXKHGcjh8p2vTesCjlbogQqLCg=",
+ "dev": true
+ },
+ "glob": {
+ "version": "7.1.6",
+ "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz",
+ "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==",
+ "dev": true,
+ "requires": {
+ "fs.realpath": "^1.0.0",
+ "inflight": "^1.0.4",
+ "inherits": "2",
+ "minimatch": "^3.0.4",
+ "once": "^1.3.0",
+ "path-is-absolute": "^1.0.0"
+ }
+ },
+ "glob-parent": {
+ "version": "5.1.1",
+ "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.1.tgz",
+ "integrity": "sha512-FnI+VGOpnlGHWZxthPGR+QhR78fuiK0sNLkHQv+bL9fQi57lNNdquIbna/WrfROrolq8GK5Ek6BiMwqL/voRYQ==",
+ "dev": true,
+ "requires": {
+ "is-glob": "^4.0.1"
+ }
+ },
+ "global-modules": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/global-modules/-/global-modules-2.0.0.tgz",
+ "integrity": "sha512-NGbfmJBp9x8IxyJSd1P+otYK8vonoJactOogrVfFRIAEY1ukil8RSKDz2Yo7wh1oihl51l/r6W4epkeKJHqL8A==",
+ "dev": true,
+ "requires": {
+ "global-prefix": "^3.0.0"
+ },
+ "dependencies": {
+ "global-prefix": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/global-prefix/-/global-prefix-3.0.0.tgz",
+ "integrity": "sha512-awConJSVCHVGND6x3tmMaKcQvwXLhjdkmomy2W+Goaui8YPgYgXJZewhg3fWC+DlfqqQuWg8AwqjGTD2nAPVWg==",
+ "dev": true,
+ "requires": {
+ "ini": "^1.3.5",
+ "kind-of": "^6.0.2",
+ "which": "^1.3.1"
+ }
+ }
+ }
+ },
+ "global-prefix": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/global-prefix/-/global-prefix-1.0.2.tgz",
+ "integrity": "sha1-2/dDxsFJklk8ZVVoy2btMsASLr4=",
+ "dev": true,
+ "requires": {
+ "expand-tilde": "^2.0.2",
+ "homedir-polyfill": "^1.0.1",
+ "ini": "^1.3.4",
+ "is-windows": "^1.0.1",
+ "which": "^1.2.14"
+ }
+ },
+ "globby": {
+ "version": "11.0.1",
+ "resolved": "https://registry.npmjs.org/globby/-/globby-11.0.1.tgz",
+ "integrity": "sha512-iH9RmgwCmUJHi2z5o2l3eTtGBtXek1OYlHrbcxOYugyHLmAsZrPj43OtHThd62Buh/Vv6VyCBD2bdyWcGNQqoQ==",
+ "dev": true,
+ "requires": {
+ "array-union": "^2.1.0",
+ "dir-glob": "^3.0.1",
+ "fast-glob": "^3.1.1",
+ "ignore": "^5.1.4",
+ "merge2": "^1.3.0",
+ "slash": "^3.0.0"
+ }
+ },
+ "graceful-fs": {
+ "version": "4.2.4",
+ "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.4.tgz",
+ "integrity": "sha512-WjKPNJF79dtJAVniUlGGWHYGz2jWxT6VhN/4m1NdkbZ2nOsEF+cI1Edgql5zCRhs/VsQYRvrXctxktVXZUkixw==",
+ "dev": true
+ },
+ "has-flag": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
+ "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=",
+ "dev": true
+ },
+ "has-value": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/has-value/-/has-value-1.0.0.tgz",
+ "integrity": "sha1-GLKB2lhbHFxR3vJMkw7SmgvmsXc=",
+ "dev": true,
+ "requires": {
+ "get-value": "^2.0.6",
+ "has-values": "^1.0.0",
+ "isobject": "^3.0.0"
+ }
+ },
+ "has-values": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/has-values/-/has-values-1.0.0.tgz",
+ "integrity": "sha1-lbC2P+whRmGab+V/51Yo1aOe/k8=",
+ "dev": true,
+ "requires": {
+ "is-number": "^3.0.0",
+ "kind-of": "^4.0.0"
+ },
+ "dependencies": {
+ "kind-of": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-4.0.0.tgz",
+ "integrity": "sha1-IIE989cSkosgc3hpGkUGb65y3Vc=",
+ "dev": true,
+ "requires": {
+ "is-buffer": "^1.1.5"
+ }
+ }
+ }
+ },
+ "hash-base": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/hash-base/-/hash-base-3.1.0.tgz",
+ "integrity": "sha512-1nmYp/rhMDiE7AYkDw+lLwlAzz0AntGIe51F3RfFfEqyQ3feY2eI/NcwC6umIQVOASPMsWJLJScWKSSvzL9IVA==",
+ "dev": true,
+ "requires": {
+ "inherits": "^2.0.4",
+ "readable-stream": "^3.6.0",
+ "safe-buffer": "^5.2.0"
+ },
+ "dependencies": {
+ "readable-stream": {
+ "version": "3.6.0",
+ "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz",
+ "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==",
+ "dev": true,
+ "requires": {
+ "inherits": "^2.0.3",
+ "string_decoder": "^1.1.1",
+ "util-deprecate": "^1.0.1"
+ }
+ },
+ "safe-buffer": {
+ "version": "5.2.1",
+ "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
+ "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==",
+ "dev": true
+ }
+ }
+ },
+ "hash.js": {
+ "version": "1.1.7",
+ "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.7.tgz",
+ "integrity": "sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==",
+ "dev": true,
+ "requires": {
+ "inherits": "^2.0.3",
+ "minimalistic-assert": "^1.0.1"
+ }
+ },
+ "he": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz",
+ "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==",
+ "dev": true
+ },
+ "hmac-drbg": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz",
+ "integrity": "sha1-0nRXAQJabHdabFRXk+1QL8DGSaE=",
+ "dev": true,
+ "requires": {
+ "hash.js": "^1.0.3",
+ "minimalistic-assert": "^1.0.0",
+ "minimalistic-crypto-utils": "^1.0.1"
+ }
+ },
+ "homedir-polyfill": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/homedir-polyfill/-/homedir-polyfill-1.0.3.tgz",
+ "integrity": "sha512-eSmmWE5bZTK2Nou4g0AI3zZ9rswp7GRKoKXS1BLUkvPviOqs4YTN1djQIqrXy9k5gEtdLPy86JjRwsNM9tnDcA==",
+ "dev": true,
+ "requires": {
+ "parse-passwd": "^1.0.0"
+ }
+ },
+ "http-proxy": {
+ "version": "1.18.1",
+ "resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.18.1.tgz",
+ "integrity": "sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ==",
+ "dev": true,
+ "requires": {
+ "eventemitter3": "^4.0.0",
+ "follow-redirects": "^1.0.0",
+ "requires-port": "^1.0.0"
+ }
+ },
+ "http-server": {
+ "version": "0.12.3",
+ "resolved": "https://registry.npmjs.org/http-server/-/http-server-0.12.3.tgz",
+ "integrity": "sha512-be0dKG6pni92bRjq0kvExtj/NrrAd28/8fCXkaI/4piTwQMSDSLMhWyW0NI1V+DBI3aa1HMlQu46/HjVLfmugA==",
+ "dev": true,
+ "requires": {
+ "basic-auth": "^1.0.3",
+ "colors": "^1.4.0",
+ "corser": "^2.0.1",
+ "ecstatic": "^3.3.2",
+ "http-proxy": "^1.18.0",
+ "minimist": "^1.2.5",
+ "opener": "^1.5.1",
+ "portfinder": "^1.0.25",
+ "secure-compare": "3.0.1",
+ "union": "~0.5.0"
+ }
+ },
+ "https-browserify": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/https-browserify/-/https-browserify-1.0.0.tgz",
+ "integrity": "sha1-7AbBDgo0wPL68Zn3/X/Hj//QPHM=",
+ "dev": true
+ },
+ "ieee754": {
+ "version": "1.1.13",
+ "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.1.13.tgz",
+ "integrity": "sha512-4vf7I2LYV/HaWerSo3XmlMkp5eZ83i+/CDluXi/IGTs/O1sejBNhTtnxzmRZfvOUqj7lZjqHkeTvpgSFDlWZTg==",
+ "dev": true
+ },
+ "iferr": {
+ "version": "0.1.5",
+ "resolved": "https://registry.npmjs.org/iferr/-/iferr-0.1.5.tgz",
+ "integrity": "sha1-xg7taebY/bazEEofy8ocGS3FtQE=",
+ "dev": true
+ },
+ "ignore": {
+ "version": "5.1.8",
+ "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.1.8.tgz",
+ "integrity": "sha512-BMpfD7PpiETpBl/A6S498BaIJ6Y/ABT93ETbby2fP00v4EbvPBXWEoaR1UBPKs3iR53pJY7EtZk5KACI57i1Uw==",
+ "dev": true
+ },
+ "import-local": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/import-local/-/import-local-2.0.0.tgz",
+ "integrity": "sha512-b6s04m3O+s3CGSbqDIyP4R6aAwAeYlVq9+WUWep6iHa8ETRf9yei1U48C5MmfJmV9AiLYYBKPMq/W+/WRpQmCQ==",
+ "dev": true,
+ "requires": {
+ "pkg-dir": "^3.0.0",
+ "resolve-cwd": "^2.0.0"
+ }
+ },
+ "imurmurhash": {
+ "version": "0.1.4",
+ "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz",
+ "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=",
+ "dev": true
+ },
+ "indent-string": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz",
+ "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==",
+ "dev": true
+ },
+ "infer-owner": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/infer-owner/-/infer-owner-1.0.4.tgz",
+ "integrity": "sha512-IClj+Xz94+d7irH5qRyfJonOdfTzuDaifE6ZPWfx0N0+/ATZCbuTPq2prFl526urkQd90WyUKIh1DfBQ2hMz9A==",
+ "dev": true
+ },
+ "inflight": {
+ "version": "1.0.6",
+ "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
+ "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=",
+ "dev": true,
+ "requires": {
+ "once": "^1.3.0",
+ "wrappy": "1"
+ }
+ },
+ "inherits": {
+ "version": "2.0.4",
+ "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
+ "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
+ "dev": true
+ },
+ "ini": {
+ "version": "1.3.5",
+ "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.5.tgz",
+ "integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==",
+ "dev": true
+ },
+ "interpret": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/interpret/-/interpret-1.4.0.tgz",
+ "integrity": "sha512-agE4QfB2Lkp9uICn7BAqoscw4SZP9kTE2hxiFI3jBPmXJfdqiahTbUuKGsMoN2GtqL9AxhYioAcVvgsb1HvRbA==",
+ "dev": true
+ },
+ "is-accessor-descriptor": {
+ "version": "0.1.6",
+ "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz",
+ "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=",
+ "dev": true,
+ "requires": {
+ "kind-of": "^3.0.2"
+ },
+ "dependencies": {
+ "kind-of": {
+ "version": "3.2.2",
+ "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
+ "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=",
+ "dev": true,
+ "requires": {
+ "is-buffer": "^1.1.5"
+ }
+ }
+ }
+ },
+ "is-binary-path": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz",
+ "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==",
+ "dev": true,
+ "optional": true,
+ "requires": {
+ "binary-extensions": "^2.0.0"
+ }
+ },
+ "is-buffer": {
+ "version": "1.1.6",
+ "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz",
+ "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==",
+ "dev": true
+ },
+ "is-data-descriptor": {
+ "version": "0.1.4",
+ "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz",
+ "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=",
+ "dev": true,
+ "requires": {
+ "kind-of": "^3.0.2"
+ },
+ "dependencies": {
+ "kind-of": {
+ "version": "3.2.2",
+ "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
+ "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=",
+ "dev": true,
+ "requires": {
+ "is-buffer": "^1.1.5"
+ }
+ }
+ }
+ },
+ "is-descriptor": {
+ "version": "0.1.6",
+ "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz",
+ "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==",
+ "dev": true,
+ "requires": {
+ "is-accessor-descriptor": "^0.1.6",
+ "is-data-descriptor": "^0.1.4",
+ "kind-of": "^5.0.0"
+ },
+ "dependencies": {
+ "kind-of": {
+ "version": "5.1.0",
+ "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz",
+ "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==",
+ "dev": true
+ }
+ }
+ },
+ "is-extendable": {
+ "version": "0.1.1",
+ "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz",
+ "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=",
+ "dev": true
+ },
+ "is-extglob": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
+ "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=",
+ "dev": true
+ },
+ "is-fullwidth-code-point": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz",
+ "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=",
+ "dev": true
+ },
+ "is-glob": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz",
+ "integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==",
+ "dev": true,
+ "requires": {
+ "is-extglob": "^2.1.1"
+ }
+ },
+ "is-number": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz",
+ "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=",
+ "dev": true,
+ "requires": {
+ "kind-of": "^3.0.2"
+ },
+ "dependencies": {
+ "kind-of": {
+ "version": "3.2.2",
+ "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
+ "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=",
+ "dev": true,
+ "requires": {
+ "is-buffer": "^1.1.5"
+ }
+ }
+ }
+ },
+ "is-plain-object": {
+ "version": "2.0.4",
+ "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz",
+ "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==",
+ "dev": true,
+ "requires": {
+ "isobject": "^3.0.1"
+ }
+ },
+ "is-windows": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz",
+ "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==",
+ "dev": true
+ },
+ "is-wsl": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-1.1.0.tgz",
+ "integrity": "sha1-HxbkqiKwTRM2tmGIpmrzxgDDpm0=",
+ "dev": true
+ },
+ "isarray": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
+ "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=",
+ "dev": true
+ },
+ "isexe": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
+ "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=",
+ "dev": true
+ },
+ "isobject": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz",
+ "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=",
+ "dev": true
+ },
+ "json-parse-better-errors": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz",
+ "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==",
+ "dev": true
+ },
+ "json-schema-traverse": {
+ "version": "0.4.1",
+ "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz",
+ "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==",
+ "dev": true
+ },
+ "json5": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz",
+ "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==",
+ "dev": true,
+ "requires": {
+ "minimist": "^1.2.0"
+ }
+ },
+ "kind-of": {
+ "version": "6.0.3",
+ "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz",
+ "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==",
+ "dev": true
+ },
+ "loader-runner": {
+ "version": "2.4.0",
+ "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-2.4.0.tgz",
+ "integrity": "sha512-Jsmr89RcXGIwivFY21FcRrisYZfvLMTWx5kOLc+JTxtpBOG6xML0vzbc6SEQG2FO9/4Fc3wW4LVcB5DmGflaRw==",
+ "dev": true
+ },
+ "loader-utils": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.4.0.tgz",
+ "integrity": "sha512-qH0WSMBtn/oHuwjy/NucEgbx5dbxxnxup9s4PVXJUDHZBQY+s0NWA9rJf53RBnQZxfch7euUui7hpoAPvALZdA==",
+ "dev": true,
+ "requires": {
+ "big.js": "^5.2.2",
+ "emojis-list": "^3.0.0",
+ "json5": "^1.0.1"
+ }
+ },
+ "locate-path": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz",
+ "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==",
+ "dev": true,
+ "requires": {
+ "p-locate": "^3.0.0",
+ "path-exists": "^3.0.0"
+ }
+ },
+ "lodash": {
+ "version": "4.17.19",
+ "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.19.tgz",
+ "integrity": "sha512-JNvd8XER9GQX0v2qJgsaN/mzFCNA5BRe/j8JN9d+tWyGLSodKQHKFicdwNYzWwI3wjRnaKPsGj1XkBjx/F96DQ==",
+ "dev": true
+ },
+ "lru-cache": {
+ "version": "5.1.1",
+ "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz",
+ "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==",
+ "dev": true,
+ "requires": {
+ "yallist": "^3.0.2"
+ }
+ },
+ "make-dir": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-2.1.0.tgz",
+ "integrity": "sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==",
+ "dev": true,
+ "requires": {
+ "pify": "^4.0.1",
+ "semver": "^5.6.0"
+ }
+ },
+ "map-cache": {
+ "version": "0.2.2",
+ "resolved": "https://registry.npmjs.org/map-cache/-/map-cache-0.2.2.tgz",
+ "integrity": "sha1-wyq9C9ZSXZsFFkW7TyasXcmKDb8=",
+ "dev": true
+ },
+ "map-visit": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/map-visit/-/map-visit-1.0.0.tgz",
+ "integrity": "sha1-7Nyo8TFE5mDxtb1B8S80edmN+48=",
+ "dev": true,
+ "requires": {
+ "object-visit": "^1.0.0"
+ }
+ },
+ "md5.js": {
+ "version": "1.3.5",
+ "resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.5.tgz",
+ "integrity": "sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg==",
+ "dev": true,
+ "requires": {
+ "hash-base": "^3.0.0",
+ "inherits": "^2.0.1",
+ "safe-buffer": "^5.1.2"
+ }
+ },
+ "memory-fs": {
+ "version": "0.4.1",
+ "resolved": "https://registry.npmjs.org/memory-fs/-/memory-fs-0.4.1.tgz",
+ "integrity": "sha1-OpoguEYlI+RHz7x+i7gO1me/xVI=",
+ "dev": true,
+ "requires": {
+ "errno": "^0.1.3",
+ "readable-stream": "^2.0.1"
+ }
+ },
+ "merge2": {
+ "version": "1.4.1",
+ "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz",
+ "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==",
+ "dev": true
+ },
+ "micromatch": {
+ "version": "3.1.10",
+ "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz",
+ "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==",
+ "dev": true,
+ "requires": {
+ "arr-diff": "^4.0.0",
+ "array-unique": "^0.3.2",
+ "braces": "^2.3.1",
+ "define-property": "^2.0.2",
+ "extend-shallow": "^3.0.2",
+ "extglob": "^2.0.4",
+ "fragment-cache": "^0.2.1",
+ "kind-of": "^6.0.2",
+ "nanomatch": "^1.2.9",
+ "object.pick": "^1.3.0",
+ "regex-not": "^1.0.0",
+ "snapdragon": "^0.8.1",
+ "to-regex": "^3.0.2"
+ }
+ },
+ "miller-rabin": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/miller-rabin/-/miller-rabin-4.0.1.tgz",
+ "integrity": "sha512-115fLhvZVqWwHPbClyntxEVfVDfl9DLLTuJvq3g2O/Oxi8AiNouAHvDSzHS0viUJc+V5vm3eq91Xwqn9dp4jRA==",
+ "dev": true,
+ "requires": {
+ "bn.js": "^4.0.0",
+ "brorand": "^1.0.1"
+ },
+ "dependencies": {
+ "bn.js": {
+ "version": "4.11.9",
+ "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.9.tgz",
+ "integrity": "sha512-E6QoYqCKZfgatHTdHzs1RRKP7ip4vvm+EyRUeE2RF0NblwVvb0p6jSVeNTOFxPn26QXN2o6SMfNxKp6kU8zQaw==",
+ "dev": true
+ }
+ }
+ },
+ "mime": {
+ "version": "1.6.0",
+ "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz",
+ "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==",
+ "dev": true
+ },
+ "minimalistic-assert": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz",
+ "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==",
+ "dev": true
+ },
+ "minimalistic-crypto-utils": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz",
+ "integrity": "sha1-9sAMHAsIIkblxNmd+4x8CDsrWCo=",
+ "dev": true
+ },
+ "minimatch": {
+ "version": "3.0.4",
+ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
+ "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==",
+ "dev": true,
+ "requires": {
+ "brace-expansion": "^1.1.7"
+ }
+ },
+ "minimist": {
+ "version": "1.2.5",
+ "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz",
+ "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==",
+ "dev": true
+ },
+ "minipass": {
+ "version": "3.1.3",
+ "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.1.3.tgz",
+ "integrity": "sha512-Mgd2GdMVzY+x3IJ+oHnVM+KG3lA5c8tnabyJKmHSaG2kAGpudxuOf8ToDkhumF7UzME7DecbQE9uOZhNm7PuJg==",
+ "dev": true,
+ "requires": {
+ "yallist": "^4.0.0"
+ },
+ "dependencies": {
+ "yallist": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
+ "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==",
+ "dev": true
+ }
+ }
+ },
+ "minipass-collect": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/minipass-collect/-/minipass-collect-1.0.2.tgz",
+ "integrity": "sha512-6T6lH0H8OG9kITm/Jm6tdooIbogG9e0tLgpY6mphXSm/A9u8Nq1ryBG+Qspiub9LjWlBPsPS3tWQ/Botq4FdxA==",
+ "dev": true,
+ "requires": {
+ "minipass": "^3.0.0"
+ }
+ },
+ "minipass-flush": {
+ "version": "1.0.5",
+ "resolved": "https://registry.npmjs.org/minipass-flush/-/minipass-flush-1.0.5.tgz",
+ "integrity": "sha512-JmQSYYpPUqX5Jyn1mXaRwOda1uQ8HP5KAT/oDSLCzt1BYRhQU0/hDtsB1ufZfEEzMZ9aAVmsBw8+FWsIXlClWw==",
+ "dev": true,
+ "requires": {
+ "minipass": "^3.0.0"
+ }
+ },
+ "minipass-pipeline": {
+ "version": "1.2.4",
+ "resolved": "https://registry.npmjs.org/minipass-pipeline/-/minipass-pipeline-1.2.4.tgz",
+ "integrity": "sha512-xuIq7cIOt09RPRJ19gdi4b+RiNvDFYe5JH+ggNvBqGqpQXcru3PcRmOZuHBKWK1Txf9+cQ+HMVN4d6z46LZP7A==",
+ "dev": true,
+ "requires": {
+ "minipass": "^3.0.0"
+ }
+ },
+ "minizlib": {
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz",
+ "integrity": "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==",
+ "dev": true,
+ "requires": {
+ "minipass": "^3.0.0",
+ "yallist": "^4.0.0"
+ },
+ "dependencies": {
+ "yallist": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
+ "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==",
+ "dev": true
+ }
+ }
+ },
+ "mississippi": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/mississippi/-/mississippi-3.0.0.tgz",
+ "integrity": "sha512-x471SsVjUtBRtcvd4BzKE9kFC+/2TeWgKCgw0bZcw1b9l2X3QX5vCWgF+KaZaYm87Ss//rHnWryupDrgLvmSkA==",
+ "dev": true,
+ "requires": {
+ "concat-stream": "^1.5.0",
+ "duplexify": "^3.4.2",
+ "end-of-stream": "^1.1.0",
+ "flush-write-stream": "^1.0.0",
+ "from2": "^2.1.0",
+ "parallel-transform": "^1.1.0",
+ "pump": "^3.0.0",
+ "pumpify": "^1.3.3",
+ "stream-each": "^1.1.0",
+ "through2": "^2.0.0"
+ }
+ },
+ "mixin-deep": {
+ "version": "1.3.2",
+ "resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.2.tgz",
+ "integrity": "sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA==",
+ "dev": true,
+ "requires": {
+ "for-in": "^1.0.2",
+ "is-extendable": "^1.0.1"
+ },
+ "dependencies": {
+ "is-extendable": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz",
+ "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==",
+ "dev": true,
+ "requires": {
+ "is-plain-object": "^2.0.4"
+ }
+ }
+ }
+ },
+ "mkdirp": {
+ "version": "0.5.5",
+ "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz",
+ "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==",
+ "dev": true,
+ "requires": {
+ "minimist": "^1.2.5"
+ }
+ },
+ "move-concurrently": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/move-concurrently/-/move-concurrently-1.0.1.tgz",
+ "integrity": "sha1-viwAX9oy4LKa8fBdfEszIUxwH5I=",
+ "dev": true,
+ "requires": {
+ "aproba": "^1.1.1",
+ "copy-concurrently": "^1.0.0",
+ "fs-write-stream-atomic": "^1.0.8",
+ "mkdirp": "^0.5.1",
+ "rimraf": "^2.5.4",
+ "run-queue": "^1.0.3"
+ }
+ },
+ "ms": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
+ "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=",
+ "dev": true
+ },
+ "nanomatch": {
+ "version": "1.2.13",
+ "resolved": "https://registry.npmjs.org/nanomatch/-/nanomatch-1.2.13.tgz",
+ "integrity": "sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA==",
+ "dev": true,
+ "requires": {
+ "arr-diff": "^4.0.0",
+ "array-unique": "^0.3.2",
+ "define-property": "^2.0.2",
+ "extend-shallow": "^3.0.2",
+ "fragment-cache": "^0.2.1",
+ "is-windows": "^1.0.2",
+ "kind-of": "^6.0.2",
+ "object.pick": "^1.3.0",
+ "regex-not": "^1.0.0",
+ "snapdragon": "^0.8.1",
+ "to-regex": "^3.0.1"
+ }
+ },
+ "neo-async": {
+ "version": "2.6.2",
+ "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz",
+ "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==",
+ "dev": true
+ },
+ "nice-try": {
+ "version": "1.0.5",
+ "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz",
+ "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==",
+ "dev": true
+ },
+ "node-libs-browser": {
+ "version": "2.2.1",
+ "resolved": "https://registry.npmjs.org/node-libs-browser/-/node-libs-browser-2.2.1.tgz",
+ "integrity": "sha512-h/zcD8H9kaDZ9ALUWwlBUDo6TKF8a7qBSCSEGfjTVIYeqsioSKaAX+BN7NgiMGp6iSIXZ3PxgCu8KS3b71YK5Q==",
+ "dev": true,
+ "requires": {
+ "assert": "^1.1.1",
+ "browserify-zlib": "^0.2.0",
+ "buffer": "^4.3.0",
+ "console-browserify": "^1.1.0",
+ "constants-browserify": "^1.0.0",
+ "crypto-browserify": "^3.11.0",
+ "domain-browser": "^1.1.1",
+ "events": "^3.0.0",
+ "https-browserify": "^1.0.0",
+ "os-browserify": "^0.3.0",
+ "path-browserify": "0.0.1",
+ "process": "^0.11.10",
+ "punycode": "^1.2.4",
+ "querystring-es3": "^0.2.0",
+ "readable-stream": "^2.3.3",
+ "stream-browserify": "^2.0.1",
+ "stream-http": "^2.7.2",
+ "string_decoder": "^1.0.0",
+ "timers-browserify": "^2.0.4",
+ "tty-browserify": "0.0.0",
+ "url": "^0.11.0",
+ "util": "^0.11.0",
+ "vm-browserify": "^1.0.1"
+ },
+ "dependencies": {
+ "punycode": {
+ "version": "1.4.1",
+ "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz",
+ "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=",
+ "dev": true
+ }
+ }
+ },
+ "normalize-path": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz",
+ "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==",
+ "dev": true
+ },
+ "object-assign": {
+ "version": "4.1.1",
+ "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
+ "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=",
+ "dev": true
+ },
+ "object-copy": {
+ "version": "0.1.0",
+ "resolved": "https://registry.npmjs.org/object-copy/-/object-copy-0.1.0.tgz",
+ "integrity": "sha1-fn2Fi3gb18mRpBupde04EnVOmYw=",
+ "dev": true,
+ "requires": {
+ "copy-descriptor": "^0.1.0",
+ "define-property": "^0.2.5",
+ "kind-of": "^3.0.3"
+ },
+ "dependencies": {
+ "define-property": {
+ "version": "0.2.5",
+ "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz",
+ "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=",
+ "dev": true,
+ "requires": {
+ "is-descriptor": "^0.1.0"
+ }
+ },
+ "kind-of": {
+ "version": "3.2.2",
+ "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
+ "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=",
+ "dev": true,
+ "requires": {
+ "is-buffer": "^1.1.5"
+ }
+ }
+ }
+ },
+ "object-visit": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/object-visit/-/object-visit-1.0.1.tgz",
+ "integrity": "sha1-95xEk68MU3e1n+OdOV5BBC3QRbs=",
+ "dev": true,
+ "requires": {
+ "isobject": "^3.0.0"
+ }
+ },
+ "object.pick": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/object.pick/-/object.pick-1.3.0.tgz",
+ "integrity": "sha1-h6EKxMFpS9Lhy/U1kaZhQftd10c=",
+ "dev": true,
+ "requires": {
+ "isobject": "^3.0.1"
+ }
+ },
+ "once": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
+ "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=",
+ "dev": true,
+ "requires": {
+ "wrappy": "1"
+ }
+ },
+ "opener": {
+ "version": "1.5.1",
+ "resolved": "https://registry.npmjs.org/opener/-/opener-1.5.1.tgz",
+ "integrity": "sha512-goYSy5c2UXE4Ra1xixabeVh1guIX/ZV/YokJksb6q2lubWu6UbvPQ20p542/sFIll1nl8JnCyK9oBaOcCWXwvA==",
+ "dev": true
+ },
+ "os-browserify": {
+ "version": "0.3.0",
+ "resolved": "https://registry.npmjs.org/os-browserify/-/os-browserify-0.3.0.tgz",
+ "integrity": "sha1-hUNzx/XCMVkU/Jv8a9gjj92h7Cc=",
+ "dev": true
+ },
+ "p-limit": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz",
+ "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==",
+ "dev": true,
+ "requires": {
+ "p-try": "^2.0.0"
+ }
+ },
+ "p-locate": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz",
+ "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==",
+ "dev": true,
+ "requires": {
+ "p-limit": "^2.0.0"
+ }
+ },
+ "p-map": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/p-map/-/p-map-4.0.0.tgz",
+ "integrity": "sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==",
+ "dev": true,
+ "requires": {
+ "aggregate-error": "^3.0.0"
+ }
+ },
+ "p-try": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz",
+ "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==",
+ "dev": true
+ },
+ "pako": {
+ "version": "1.0.11",
+ "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz",
+ "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==",
+ "dev": true
+ },
+ "parallel-transform": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/parallel-transform/-/parallel-transform-1.2.0.tgz",
+ "integrity": "sha512-P2vSmIu38uIlvdcU7fDkyrxj33gTUy/ABO5ZUbGowxNCopBq/OoD42bP4UmMrJoPyk4Uqf0mu3mtWBhHCZD8yg==",
+ "dev": true,
+ "requires": {
+ "cyclist": "^1.0.1",
+ "inherits": "^2.0.3",
+ "readable-stream": "^2.1.5"
+ }
+ },
+ "parse-asn1": {
+ "version": "5.1.6",
+ "resolved": "https://registry.npmjs.org/parse-asn1/-/parse-asn1-5.1.6.tgz",
+ "integrity": "sha512-RnZRo1EPU6JBnra2vGHj0yhp6ebyjBZpmUCLHWiFhxlzvBCCpAuZ7elsBp1PVAbQN0/04VD/19rfzlBSwLstMw==",
+ "dev": true,
+ "requires": {
+ "asn1.js": "^5.2.0",
+ "browserify-aes": "^1.0.0",
+ "evp_bytestokey": "^1.0.0",
+ "pbkdf2": "^3.0.3",
+ "safe-buffer": "^5.1.1"
+ }
+ },
+ "parse-passwd": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/parse-passwd/-/parse-passwd-1.0.0.tgz",
+ "integrity": "sha1-bVuTSkVpk7I9N/QKOC1vFmao5cY=",
+ "dev": true
+ },
+ "pascalcase": {
+ "version": "0.1.1",
+ "resolved": "https://registry.npmjs.org/pascalcase/-/pascalcase-0.1.1.tgz",
+ "integrity": "sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ=",
+ "dev": true
+ },
+ "path-browserify": {
+ "version": "0.0.1",
+ "resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-0.0.1.tgz",
+ "integrity": "sha512-BapA40NHICOS+USX9SN4tyhq+A2RrN/Ws5F0Z5aMHDp98Fl86lX8Oti8B7uN93L4Ifv4fHOEA+pQw87gmMO/lQ==",
+ "dev": true
+ },
+ "path-dirname": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/path-dirname/-/path-dirname-1.0.2.tgz",
+ "integrity": "sha1-zDPSTVJeCZpTiMAzbG4yuRYGCeA=",
+ "dev": true,
+ "optional": true
+ },
+ "path-exists": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz",
+ "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=",
+ "dev": true
+ },
+ "path-is-absolute": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
+ "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=",
+ "dev": true
+ },
+ "path-key": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz",
+ "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=",
+ "dev": true
+ },
+ "path-type": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz",
+ "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==",
+ "dev": true
+ },
+ "pbkdf2": {
+ "version": "3.1.1",
+ "resolved": "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.1.1.tgz",
+ "integrity": "sha512-4Ejy1OPxi9f2tt1rRV7Go7zmfDQ+ZectEQz3VGUQhgq62HtIRPDyG/JtnwIxs6x3uNMwo2V7q1fMvKjb+Tnpqg==",
+ "dev": true,
+ "requires": {
+ "create-hash": "^1.1.2",
+ "create-hmac": "^1.1.4",
+ "ripemd160": "^2.0.1",
+ "safe-buffer": "^5.0.1",
+ "sha.js": "^2.4.8"
+ }
+ },
+ "picomatch": {
+ "version": "2.2.2",
+ "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.2.2.tgz",
+ "integrity": "sha512-q0M/9eZHzmr0AulXyPwNfZjtwZ/RBZlbN3K3CErVrk50T2ASYI7Bye0EvekFY3IP1Nt2DHu0re+V2ZHIpMkuWg==",
+ "dev": true
+ },
+ "pify": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz",
+ "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==",
+ "dev": true
+ },
+ "pkg-dir": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-3.0.0.tgz",
+ "integrity": "sha512-/E57AYkoeQ25qkxMj5PBOVgF8Kiu/h7cYS30Z5+R7WaiCCBfLq58ZI/dSeaEKb9WVJV5n/03QwrN3IeWIFllvw==",
+ "dev": true,
+ "requires": {
+ "find-up": "^3.0.0"
+ }
+ },
+ "portfinder": {
+ "version": "1.0.28",
+ "resolved": "https://registry.npmjs.org/portfinder/-/portfinder-1.0.28.tgz",
+ "integrity": "sha512-Se+2isanIcEqf2XMHjyUKskczxbPH7dQnlMjXX6+dybayyHvAf/TCgyMRlzf/B6QDhAEFOGes0pzRo3by4AbMA==",
+ "dev": true,
+ "requires": {
+ "async": "^2.6.2",
+ "debug": "^3.1.1",
+ "mkdirp": "^0.5.5"
+ },
+ "dependencies": {
+ "debug": {
+ "version": "3.2.6",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz",
+ "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==",
+ "dev": true,
+ "requires": {
+ "ms": "^2.1.1"
+ }
+ },
+ "ms": {
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
+ "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
+ "dev": true
+ }
+ }
+ },
+ "posix-character-classes": {
+ "version": "0.1.1",
+ "resolved": "https://registry.npmjs.org/posix-character-classes/-/posix-character-classes-0.1.1.tgz",
+ "integrity": "sha1-AerA/jta9xoqbAL+q7jB/vfgDqs=",
+ "dev": true
+ },
+ "process": {
+ "version": "0.11.10",
+ "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz",
+ "integrity": "sha1-czIwDoQBYb2j5podHZGn1LwW8YI=",
+ "dev": true
+ },
+ "process-nextick-args": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz",
+ "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==",
+ "dev": true
+ },
+ "promise-inflight": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/promise-inflight/-/promise-inflight-1.0.1.tgz",
+ "integrity": "sha1-mEcocL8igTL8vdhoEputEsPAKeM=",
+ "dev": true
+ },
+ "prr": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/prr/-/prr-1.0.1.tgz",
+ "integrity": "sha1-0/wRS6BplaRexok/SEzrHXj19HY=",
+ "dev": true
+ },
+ "public-encrypt": {
+ "version": "4.0.3",
+ "resolved": "https://registry.npmjs.org/public-encrypt/-/public-encrypt-4.0.3.tgz",
+ "integrity": "sha512-zVpa8oKZSz5bTMTFClc1fQOnyyEzpl5ozpi1B5YcvBrdohMjH2rfsBtyXcuNuwjsDIXmBYlF2N5FlJYhR29t8Q==",
+ "dev": true,
+ "requires": {
+ "bn.js": "^4.1.0",
+ "browserify-rsa": "^4.0.0",
+ "create-hash": "^1.1.0",
+ "parse-asn1": "^5.0.0",
+ "randombytes": "^2.0.1",
+ "safe-buffer": "^5.1.2"
+ },
+ "dependencies": {
+ "bn.js": {
+ "version": "4.11.9",
+ "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.9.tgz",
+ "integrity": "sha512-E6QoYqCKZfgatHTdHzs1RRKP7ip4vvm+EyRUeE2RF0NblwVvb0p6jSVeNTOFxPn26QXN2o6SMfNxKp6kU8zQaw==",
+ "dev": true
+ }
+ }
+ },
+ "pump": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz",
+ "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==",
+ "dev": true,
+ "requires": {
+ "end-of-stream": "^1.1.0",
+ "once": "^1.3.1"
+ }
+ },
+ "pumpify": {
+ "version": "1.5.1",
+ "resolved": "https://registry.npmjs.org/pumpify/-/pumpify-1.5.1.tgz",
+ "integrity": "sha512-oClZI37HvuUJJxSKKrC17bZ9Cu0ZYhEAGPsPUy9KlMUmv9dKX2o77RUmq7f3XjIxbwyGwYzbzQ1L2Ks8sIradQ==",
+ "dev": true,
+ "requires": {
+ "duplexify": "^3.6.0",
+ "inherits": "^2.0.3",
+ "pump": "^2.0.0"
+ },
+ "dependencies": {
+ "pump": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/pump/-/pump-2.0.1.tgz",
+ "integrity": "sha512-ruPMNRkN3MHP1cWJc9OWr+T/xDP0jhXYCLfJcBuX54hhfIBnaQmAUMfDcG4DM5UMWByBbJY69QSphm3jtDKIkA==",
+ "dev": true,
+ "requires": {
+ "end-of-stream": "^1.1.0",
+ "once": "^1.3.1"
+ }
+ }
+ }
+ },
+ "punycode": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz",
+ "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==",
+ "dev": true
+ },
+ "qs": {
+ "version": "6.9.4",
+ "resolved": "https://registry.npmjs.org/qs/-/qs-6.9.4.tgz",
+ "integrity": "sha512-A1kFqHekCTM7cz0udomYUoYNWjBebHm/5wzU/XqrBRBNWectVH0QIiN+NEcZ0Dte5hvzHwbr8+XQmguPhJ6WdQ==",
+ "dev": true
+ },
+ "querystring": {
+ "version": "0.2.0",
+ "resolved": "https://registry.npmjs.org/querystring/-/querystring-0.2.0.tgz",
+ "integrity": "sha1-sgmEkgO7Jd+CDadW50cAWHhSFiA=",
+ "dev": true
+ },
+ "querystring-es3": {
+ "version": "0.2.1",
+ "resolved": "https://registry.npmjs.org/querystring-es3/-/querystring-es3-0.2.1.tgz",
+ "integrity": "sha1-nsYfeQSYdXB9aUFFlv2Qek1xHnM=",
+ "dev": true
+ },
+ "randombytes": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz",
+ "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==",
+ "dev": true,
+ "requires": {
+ "safe-buffer": "^5.1.0"
+ }
+ },
+ "randomfill": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/randomfill/-/randomfill-1.0.4.tgz",
+ "integrity": "sha512-87lcbR8+MhcWcUiQ+9e+Rwx8MyR2P7qnt15ynUlbm3TU/fjbgz4GsvfSUDTemtCCtVCqb4ZcEFlyPNTh9bBTLw==",
+ "dev": true,
+ "requires": {
+ "randombytes": "^2.0.5",
+ "safe-buffer": "^5.1.0"
+ }
+ },
+ "readable-stream": {
+ "version": "2.3.7",
+ "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz",
+ "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==",
+ "dev": true,
+ "requires": {
+ "core-util-is": "~1.0.0",
+ "inherits": "~2.0.3",
+ "isarray": "~1.0.0",
+ "process-nextick-args": "~2.0.0",
+ "safe-buffer": "~5.1.1",
+ "string_decoder": "~1.1.1",
+ "util-deprecate": "~1.0.1"
+ }
+ },
+ "readdirp": {
+ "version": "3.5.0",
+ "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.5.0.tgz",
+ "integrity": "sha512-cMhu7c/8rdhkHXWsY+osBhfSy0JikwpHK/5+imo+LpeasTF8ouErHrlYkwT0++njiyuDvc7OFY5T3ukvZ8qmFQ==",
+ "dev": true,
+ "optional": true,
+ "requires": {
+ "picomatch": "^2.2.1"
+ }
+ },
+ "regex-not": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/regex-not/-/regex-not-1.0.2.tgz",
+ "integrity": "sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A==",
+ "dev": true,
+ "requires": {
+ "extend-shallow": "^3.0.2",
+ "safe-regex": "^1.1.0"
+ }
+ },
+ "remove-trailing-separator": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz",
+ "integrity": "sha1-wkvOKig62tW8P1jg1IJJuSN52O8=",
+ "dev": true,
+ "optional": true
+ },
+ "repeat-element": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.3.tgz",
+ "integrity": "sha512-ahGq0ZnV5m5XtZLMb+vP76kcAM5nkLqk0lpqAuojSKGgQtn4eRi4ZZGm2olo2zKFH+sMsWaqOCW1dqAnOru72g==",
+ "dev": true
+ },
+ "repeat-string": {
+ "version": "1.6.1",
+ "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz",
+ "integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc=",
+ "dev": true
+ },
+ "require-directory": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz",
+ "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=",
+ "dev": true
+ },
+ "require-main-filename": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz",
+ "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==",
+ "dev": true
+ },
+ "requires-port": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz",
+ "integrity": "sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8=",
+ "dev": true
+ },
+ "resolve-cwd": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-2.0.0.tgz",
+ "integrity": "sha1-AKn3OHVW4nA46uIyyqNypqWbZlo=",
+ "dev": true,
+ "requires": {
+ "resolve-from": "^3.0.0"
+ }
+ },
+ "resolve-dir": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/resolve-dir/-/resolve-dir-1.0.1.tgz",
+ "integrity": "sha1-eaQGRMNivoLybv/nOcm7U4IEb0M=",
+ "dev": true,
+ "requires": {
+ "expand-tilde": "^2.0.0",
+ "global-modules": "^1.0.0"
+ },
+ "dependencies": {
+ "global-modules": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/global-modules/-/global-modules-1.0.0.tgz",
+ "integrity": "sha512-sKzpEkf11GpOFuw0Zzjzmt4B4UZwjOcG757PPvrfhxcLFbq0wpsgpOqxpxtxFiCG4DtG93M6XRVbF2oGdev7bg==",
+ "dev": true,
+ "requires": {
+ "global-prefix": "^1.0.1",
+ "is-windows": "^1.0.1",
+ "resolve-dir": "^1.0.0"
+ }
+ }
+ }
+ },
+ "resolve-from": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-3.0.0.tgz",
+ "integrity": "sha1-six699nWiBvItuZTM17rywoYh0g=",
+ "dev": true
+ },
+ "resolve-url": {
+ "version": "0.2.1",
+ "resolved": "https://registry.npmjs.org/resolve-url/-/resolve-url-0.2.1.tgz",
+ "integrity": "sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo=",
+ "dev": true
+ },
+ "ret": {
+ "version": "0.1.15",
+ "resolved": "https://registry.npmjs.org/ret/-/ret-0.1.15.tgz",
+ "integrity": "sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==",
+ "dev": true
+ },
+ "reusify": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz",
+ "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==",
+ "dev": true
+ },
+ "rimraf": {
+ "version": "2.7.1",
+ "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz",
+ "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==",
+ "dev": true,
+ "requires": {
+ "glob": "^7.1.3"
+ }
+ },
+ "ripemd160": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/ripemd160/-/ripemd160-2.0.2.tgz",
+ "integrity": "sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA==",
+ "dev": true,
+ "requires": {
+ "hash-base": "^3.0.0",
+ "inherits": "^2.0.1"
+ }
+ },
+ "run-parallel": {
+ "version": "1.1.9",
+ "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.1.9.tgz",
+ "integrity": "sha512-DEqnSRTDw/Tc3FXf49zedI638Z9onwUotBMiUFKmrO2sdFKIbXamXGQ3Axd4qgphxKB4kw/qP1w5kTxnfU1B9Q==",
+ "dev": true
+ },
+ "run-queue": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/run-queue/-/run-queue-1.0.3.tgz",
+ "integrity": "sha1-6Eg5bwV9Ij8kOGkkYY4laUFh7Ec=",
+ "dev": true,
+ "requires": {
+ "aproba": "^1.1.1"
+ }
+ },
+ "safe-buffer": {
+ "version": "5.1.2",
+ "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
+ "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==",
+ "dev": true
+ },
+ "safe-regex": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz",
+ "integrity": "sha1-QKNmnzsHfR6UPURinhV91IAjvy4=",
+ "dev": true,
+ "requires": {
+ "ret": "~0.1.10"
+ }
+ },
+ "safer-buffer": {
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
+ "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==",
+ "dev": true
+ },
+ "schema-utils": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-1.0.0.tgz",
+ "integrity": "sha512-i27Mic4KovM/lnGsy8whRCHhc7VicJajAjTrYg11K9zfZXnYIt4k5F+kZkwjnrhKzLic/HLU4j11mjsz2G/75g==",
+ "dev": true,
+ "requires": {
+ "ajv": "^6.1.0",
+ "ajv-errors": "^1.0.0",
+ "ajv-keywords": "^3.1.0"
+ }
+ },
+ "secure-compare": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/secure-compare/-/secure-compare-3.0.1.tgz",
+ "integrity": "sha1-8aAymzCLIh+uN7mXTz1XjQypmeM=",
+ "dev": true
+ },
+ "semver": {
+ "version": "5.7.1",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz",
+ "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==",
+ "dev": true
+ },
+ "serialize-javascript": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-4.0.0.tgz",
+ "integrity": "sha512-GaNA54380uFefWghODBWEGisLZFj00nS5ACs6yHa9nLqlLpVLO8ChDGeKRjZnV4Nh4n0Qi7nhYZD/9fCPzEqkw==",
+ "dev": true,
+ "requires": {
+ "randombytes": "^2.1.0"
+ }
+ },
+ "set-blocking": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz",
+ "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=",
+ "dev": true
+ },
+ "set-value": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.1.tgz",
+ "integrity": "sha512-JxHc1weCN68wRY0fhCoXpyK55m/XPHafOmK4UWD7m2CI14GMcFypt4w/0+NV5f/ZMby2F6S2wwA7fgynh9gWSw==",
+ "dev": true,
+ "requires": {
+ "extend-shallow": "^2.0.1",
+ "is-extendable": "^0.1.1",
+ "is-plain-object": "^2.0.3",
+ "split-string": "^3.0.1"
+ },
+ "dependencies": {
+ "extend-shallow": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
+ "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=",
+ "dev": true,
+ "requires": {
+ "is-extendable": "^0.1.0"
+ }
+ }
+ }
+ },
+ "setimmediate": {
+ "version": "1.0.5",
+ "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz",
+ "integrity": "sha1-KQy7Iy4waULX1+qbg3Mqt4VvgoU=",
+ "dev": true
+ },
+ "sha.js": {
+ "version": "2.4.11",
+ "resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.11.tgz",
+ "integrity": "sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==",
+ "dev": true,
+ "requires": {
+ "inherits": "^2.0.1",
+ "safe-buffer": "^5.0.1"
+ }
+ },
+ "shebang-command": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz",
+ "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=",
+ "dev": true,
+ "requires": {
+ "shebang-regex": "^1.0.0"
+ }
+ },
+ "shebang-regex": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz",
+ "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=",
+ "dev": true
+ },
+ "slash": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz",
+ "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==",
+ "dev": true
+ },
+ "snapdragon": {
+ "version": "0.8.2",
+ "resolved": "https://registry.npmjs.org/snapdragon/-/snapdragon-0.8.2.tgz",
+ "integrity": "sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg==",
+ "dev": true,
+ "requires": {
+ "base": "^0.11.1",
+ "debug": "^2.2.0",
+ "define-property": "^0.2.5",
+ "extend-shallow": "^2.0.1",
+ "map-cache": "^0.2.2",
+ "source-map": "^0.5.6",
+ "source-map-resolve": "^0.5.0",
+ "use": "^3.1.0"
+ },
+ "dependencies": {
+ "define-property": {
+ "version": "0.2.5",
+ "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz",
+ "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=",
+ "dev": true,
+ "requires": {
+ "is-descriptor": "^0.1.0"
+ }
+ },
+ "extend-shallow": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
+ "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=",
+ "dev": true,
+ "requires": {
+ "is-extendable": "^0.1.0"
+ }
+ }
+ }
+ },
+ "snapdragon-node": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/snapdragon-node/-/snapdragon-node-2.1.1.tgz",
+ "integrity": "sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw==",
+ "dev": true,
+ "requires": {
+ "define-property": "^1.0.0",
+ "isobject": "^3.0.0",
+ "snapdragon-util": "^3.0.1"
+ },
+ "dependencies": {
+ "define-property": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz",
+ "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=",
+ "dev": true,
+ "requires": {
+ "is-descriptor": "^1.0.0"
+ }
+ },
+ "is-accessor-descriptor": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz",
+ "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==",
+ "dev": true,
+ "requires": {
+ "kind-of": "^6.0.0"
+ }
+ },
+ "is-data-descriptor": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz",
+ "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==",
+ "dev": true,
+ "requires": {
+ "kind-of": "^6.0.0"
+ }
+ },
+ "is-descriptor": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz",
+ "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==",
+ "dev": true,
+ "requires": {
+ "is-accessor-descriptor": "^1.0.0",
+ "is-data-descriptor": "^1.0.0",
+ "kind-of": "^6.0.2"
+ }
+ }
+ }
+ },
+ "snapdragon-util": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/snapdragon-util/-/snapdragon-util-3.0.1.tgz",
+ "integrity": "sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ==",
+ "dev": true,
+ "requires": {
+ "kind-of": "^3.2.0"
+ },
+ "dependencies": {
+ "kind-of": {
+ "version": "3.2.2",
+ "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
+ "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=",
+ "dev": true,
+ "requires": {
+ "is-buffer": "^1.1.5"
+ }
+ }
+ }
+ },
+ "source-list-map": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/source-list-map/-/source-list-map-2.0.1.tgz",
+ "integrity": "sha512-qnQ7gVMxGNxsiL4lEuJwe/To8UnK7fAnmbGEEH8RpLouuKbeEm0lhbQVFIrNSuB+G7tVrAlVsZgETT5nljf+Iw==",
+ "dev": true
+ },
+ "source-map": {
+ "version": "0.5.7",
+ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
+ "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=",
+ "dev": true
+ },
+ "source-map-resolve": {
+ "version": "0.5.3",
+ "resolved": "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.5.3.tgz",
+ "integrity": "sha512-Htz+RnsXWk5+P2slx5Jh3Q66vhQj1Cllm0zvnaY98+NFx+Dv2CF/f5O/t8x+KaNdrdIAsruNzoh/KpialbqAnw==",
+ "dev": true,
+ "requires": {
+ "atob": "^2.1.2",
+ "decode-uri-component": "^0.2.0",
+ "resolve-url": "^0.2.1",
+ "source-map-url": "^0.4.0",
+ "urix": "^0.1.0"
+ }
+ },
+ "source-map-support": {
+ "version": "0.5.19",
+ "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.19.tgz",
+ "integrity": "sha512-Wonm7zOCIJzBGQdB+thsPar0kYuCIzYvxZwlBa87yi/Mdjv7Tip2cyVbLj5o0cFPN4EVkuTwb3GDDyUx2DGnGw==",
+ "dev": true,
+ "requires": {
+ "buffer-from": "^1.0.0",
+ "source-map": "^0.6.0"
+ },
+ "dependencies": {
+ "source-map": {
+ "version": "0.6.1",
+ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
+ "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
+ "dev": true
+ }
+ }
+ },
+ "source-map-url": {
+ "version": "0.4.0",
+ "resolved": "https://registry.npmjs.org/source-map-url/-/source-map-url-0.4.0.tgz",
+ "integrity": "sha1-PpNdfd1zYxuXZZlW1VEo6HtQhKM=",
+ "dev": true
+ },
+ "split-string": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/split-string/-/split-string-3.1.0.tgz",
+ "integrity": "sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw==",
+ "dev": true,
+ "requires": {
+ "extend-shallow": "^3.0.0"
+ }
+ },
+ "ssri": {
+ "version": "6.0.1",
+ "resolved": "https://registry.npmjs.org/ssri/-/ssri-6.0.1.tgz",
+ "integrity": "sha512-3Wge10hNcT1Kur4PDFwEieXSCMCJs/7WvSACcrMYrNp+b8kDL1/0wJch5Ni2WrtwEa2IO8OsVfeKIciKCDx/QA==",
+ "dev": true,
+ "requires": {
+ "figgy-pudding": "^3.5.1"
+ }
+ },
+ "static-extend": {
+ "version": "0.1.2",
+ "resolved": "https://registry.npmjs.org/static-extend/-/static-extend-0.1.2.tgz",
+ "integrity": "sha1-YICcOcv/VTNyJv1eC1IPNB8ftcY=",
+ "dev": true,
+ "requires": {
+ "define-property": "^0.2.5",
+ "object-copy": "^0.1.0"
+ },
+ "dependencies": {
+ "define-property": {
+ "version": "0.2.5",
+ "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz",
+ "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=",
+ "dev": true,
+ "requires": {
+ "is-descriptor": "^0.1.0"
+ }
+ }
+ }
+ },
+ "stream-browserify": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/stream-browserify/-/stream-browserify-2.0.2.tgz",
+ "integrity": "sha512-nX6hmklHs/gr2FuxYDltq8fJA1GDlxKQCz8O/IM4atRqBH8OORmBNgfvW5gG10GT/qQ9u0CzIvr2X5Pkt6ntqg==",
+ "dev": true,
+ "requires": {
+ "inherits": "~2.0.1",
+ "readable-stream": "^2.0.2"
+ }
+ },
+ "stream-each": {
+ "version": "1.2.3",
+ "resolved": "https://registry.npmjs.org/stream-each/-/stream-each-1.2.3.tgz",
+ "integrity": "sha512-vlMC2f8I2u/bZGqkdfLQW/13Zihpej/7PmSiMQsbYddxuTsJp8vRe2x2FvVExZg7FaOds43ROAuFJwPR4MTZLw==",
+ "dev": true,
+ "requires": {
+ "end-of-stream": "^1.1.0",
+ "stream-shift": "^1.0.0"
+ }
+ },
+ "stream-http": {
+ "version": "2.8.3",
+ "resolved": "https://registry.npmjs.org/stream-http/-/stream-http-2.8.3.tgz",
+ "integrity": "sha512-+TSkfINHDo4J+ZobQLWiMouQYB+UVYFttRA94FpEzzJ7ZdqcL4uUUQ7WkdkI4DSozGmgBUE/a47L+38PenXhUw==",
+ "dev": true,
+ "requires": {
+ "builtin-status-codes": "^3.0.0",
+ "inherits": "^2.0.1",
+ "readable-stream": "^2.3.6",
+ "to-arraybuffer": "^1.0.0",
+ "xtend": "^4.0.0"
+ }
+ },
+ "stream-shift": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/stream-shift/-/stream-shift-1.0.1.tgz",
+ "integrity": "sha512-AiisoFqQ0vbGcZgQPY1cdP2I76glaVA/RauYR4G4thNFgkTqr90yXTo4LYX60Jl+sIlPNHHdGSwo01AvbKUSVQ==",
+ "dev": true
+ },
+ "string-width": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz",
+ "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==",
+ "dev": true,
+ "requires": {
+ "emoji-regex": "^7.0.1",
+ "is-fullwidth-code-point": "^2.0.0",
+ "strip-ansi": "^5.1.0"
+ }
+ },
+ "string_decoder": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
+ "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
+ "dev": true,
+ "requires": {
+ "safe-buffer": "~5.1.0"
+ }
+ },
+ "strip-ansi": {
+ "version": "5.2.0",
+ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz",
+ "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==",
+ "dev": true,
+ "requires": {
+ "ansi-regex": "^4.1.0"
+ }
+ },
+ "supports-color": {
+ "version": "6.1.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz",
+ "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==",
+ "dev": true,
+ "requires": {
+ "has-flag": "^3.0.0"
+ }
+ },
+ "tapable": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/tapable/-/tapable-1.1.3.tgz",
+ "integrity": "sha512-4WK/bYZmj8xLr+HUCODHGF1ZFzsYffasLUgEiMBY4fgtltdO6B4WJtlSbPaDTLpYTcGVwM2qLnFTICEcNxs3kA==",
+ "dev": true
+ },
+ "tar": {
+ "version": "6.0.5",
+ "resolved": "https://registry.npmjs.org/tar/-/tar-6.0.5.tgz",
+ "integrity": "sha512-0b4HOimQHj9nXNEAA7zWwMM91Zhhba3pspja6sQbgTpynOJf+bkjBnfybNYzbpLbnwXnbyB4LOREvlyXLkCHSg==",
+ "dev": true,
+ "requires": {
+ "chownr": "^2.0.0",
+ "fs-minipass": "^2.0.0",
+ "minipass": "^3.0.0",
+ "minizlib": "^2.1.1",
+ "mkdirp": "^1.0.3",
+ "yallist": "^4.0.0"
+ },
+ "dependencies": {
+ "chownr": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz",
+ "integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==",
+ "dev": true
+ },
+ "mkdirp": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz",
+ "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==",
+ "dev": true
+ },
+ "yallist": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
+ "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==",
+ "dev": true
+ }
+ }
+ },
+ "terser": {
+ "version": "4.8.0",
+ "resolved": "https://registry.npmjs.org/terser/-/terser-4.8.0.tgz",
+ "integrity": "sha512-EAPipTNeWsb/3wLPeup1tVPaXfIaU68xMnVdPafIL1TV05OhASArYyIfFvnvJCNrR2NIOvDVNNTFRa+Re2MWyw==",
+ "dev": true,
+ "requires": {
+ "commander": "^2.20.0",
+ "source-map": "~0.6.1",
+ "source-map-support": "~0.5.12"
+ },
+ "dependencies": {
+ "source-map": {
+ "version": "0.6.1",
+ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
+ "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
+ "dev": true
+ }
+ }
+ },
+ "terser-webpack-plugin": {
+ "version": "1.4.5",
+ "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-1.4.5.tgz",
+ "integrity": "sha512-04Rfe496lN8EYruwi6oPQkG0vo8C+HT49X687FZnpPF0qMAIHONI6HEXYPKDOE8e5HjXTyKfqRd/agHtH0kOtw==",
+ "dev": true,
+ "requires": {
+ "cacache": "^12.0.2",
+ "find-cache-dir": "^2.1.0",
+ "is-wsl": "^1.1.0",
+ "schema-utils": "^1.0.0",
+ "serialize-javascript": "^4.0.0",
+ "source-map": "^0.6.1",
+ "terser": "^4.1.2",
+ "webpack-sources": "^1.4.0",
+ "worker-farm": "^1.7.0"
+ },
+ "dependencies": {
+ "source-map": {
+ "version": "0.6.1",
+ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
+ "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
+ "dev": true
+ }
+ }
+ },
+ "through2": {
+ "version": "2.0.5",
+ "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz",
+ "integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==",
+ "dev": true,
+ "requires": {
+ "readable-stream": "~2.3.6",
+ "xtend": "~4.0.1"
+ }
+ },
+ "timers-browserify": {
+ "version": "2.0.11",
+ "resolved": "https://registry.npmjs.org/timers-browserify/-/timers-browserify-2.0.11.tgz",
+ "integrity": "sha512-60aV6sgJ5YEbzUdn9c8kYGIqOubPoUdqQCul3SBAsRCZ40s6Y5cMcrW4dt3/k/EsbLVJNl9n6Vz3fTc+k2GeKQ==",
+ "dev": true,
+ "requires": {
+ "setimmediate": "^1.0.4"
+ }
+ },
+ "to-arraybuffer": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/to-arraybuffer/-/to-arraybuffer-1.0.1.tgz",
+ "integrity": "sha1-fSKbH8xjfkZsoIEYCDanqr/4P0M=",
+ "dev": true
+ },
+ "to-object-path": {
+ "version": "0.3.0",
+ "resolved": "https://registry.npmjs.org/to-object-path/-/to-object-path-0.3.0.tgz",
+ "integrity": "sha1-KXWIt7Dn4KwI4E5nL4XB9JmeF68=",
+ "dev": true,
+ "requires": {
+ "kind-of": "^3.0.2"
+ },
+ "dependencies": {
+ "kind-of": {
+ "version": "3.2.2",
+ "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
+ "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=",
+ "dev": true,
+ "requires": {
+ "is-buffer": "^1.1.5"
+ }
+ }
+ }
+ },
+ "to-regex": {
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/to-regex/-/to-regex-3.0.2.tgz",
+ "integrity": "sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw==",
+ "dev": true,
+ "requires": {
+ "define-property": "^2.0.2",
+ "extend-shallow": "^3.0.2",
+ "regex-not": "^1.0.2",
+ "safe-regex": "^1.1.0"
+ }
+ },
+ "to-regex-range": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz",
+ "integrity": "sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=",
+ "dev": true,
+ "requires": {
+ "is-number": "^3.0.0",
+ "repeat-string": "^1.6.1"
+ }
+ },
+ "ts-loader": {
+ "version": "8.0.3",
+ "resolved": "https://registry.npmjs.org/ts-loader/-/ts-loader-8.0.3.tgz",
+ "integrity": "sha512-wsqfnVdB7xQiqhqbz2ZPLGHLPZbHVV5Qn/MNFZkCFxRU1miDyxKORucDGxKtsQJ63Rfza0udiUxWF5nHY6bpdQ==",
+ "dev": true,
+ "requires": {
+ "chalk": "^2.3.0",
+ "enhanced-resolve": "^4.0.0",
+ "loader-utils": "^1.0.2",
+ "micromatch": "^4.0.0",
+ "semver": "^6.0.0"
+ },
+ "dependencies": {
+ "braces": {
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz",
+ "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==",
+ "dev": true,
+ "requires": {
+ "fill-range": "^7.0.1"
+ }
+ },
+ "fill-range": {
+ "version": "7.0.1",
+ "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz",
+ "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==",
+ "dev": true,
+ "requires": {
+ "to-regex-range": "^5.0.1"
+ }
+ },
+ "is-number": {
+ "version": "7.0.0",
+ "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
+ "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
+ "dev": true
+ },
+ "micromatch": {
+ "version": "4.0.2",
+ "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.2.tgz",
+ "integrity": "sha512-y7FpHSbMUMoyPbYUSzO6PaZ6FyRnQOpHuKwbo1G+Knck95XVU4QAiKdGEnj5wwoS7PlOgthX/09u5iFJ+aYf5Q==",
+ "dev": true,
+ "requires": {
+ "braces": "^3.0.1",
+ "picomatch": "^2.0.5"
+ }
+ },
+ "semver": {
+ "version": "6.3.0",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
+ "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
+ "dev": true
+ },
+ "to-regex-range": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
+ "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
+ "dev": true,
+ "requires": {
+ "is-number": "^7.0.0"
+ }
+ }
+ }
+ },
+ "tslib": {
+ "version": "1.14.1",
+ "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz",
+ "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==",
+ "dev": true
+ },
+ "tty-browserify": {
+ "version": "0.0.0",
+ "resolved": "https://registry.npmjs.org/tty-browserify/-/tty-browserify-0.0.0.tgz",
+ "integrity": "sha1-oVe6QC2iTpv5V/mqadUk7tQpAaY=",
+ "dev": true
+ },
+ "typedarray": {
+ "version": "0.0.6",
+ "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz",
+ "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=",
+ "dev": true
+ },
+ "typescript": {
+ "version": "4.0.2",
+ "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.0.2.tgz",
+ "integrity": "sha512-e4ERvRV2wb+rRZ/IQeb3jm2VxBsirQLpQhdxplZ2MEzGvDkkMmPglecnNDfSUBivMjP93vRbngYYDQqQ/78bcQ==",
+ "dev": true
+ },
+ "union": {
+ "version": "0.5.0",
+ "resolved": "https://registry.npmjs.org/union/-/union-0.5.0.tgz",
+ "integrity": "sha512-N6uOhuW6zO95P3Mel2I2zMsbsanvvtgn6jVqJv4vbVcz/JN0OkL9suomjQGmWtxJQXOCqUJvquc1sMeNz/IwlA==",
+ "dev": true,
+ "requires": {
+ "qs": "^6.4.0"
+ }
+ },
+ "union-value": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.1.tgz",
+ "integrity": "sha512-tJfXmxMeWYnczCVs7XAEvIV7ieppALdyepWMkHkwciRpZraG/xwT+s2JN8+pr1+8jCRf80FFzvr+MpQeeoF4Xg==",
+ "dev": true,
+ "requires": {
+ "arr-union": "^3.1.0",
+ "get-value": "^2.0.6",
+ "is-extendable": "^0.1.1",
+ "set-value": "^2.0.1"
+ }
+ },
+ "unique-filename": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/unique-filename/-/unique-filename-1.1.1.tgz",
+ "integrity": "sha512-Vmp0jIp2ln35UTXuryvjzkjGdRyf9b2lTXuSYUiPmzRcl3FDtYqAwOnTJkAngD9SWhnoJzDbTKwaOrZ+STtxNQ==",
+ "dev": true,
+ "requires": {
+ "unique-slug": "^2.0.0"
+ }
+ },
+ "unique-slug": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/unique-slug/-/unique-slug-2.0.2.tgz",
+ "integrity": "sha512-zoWr9ObaxALD3DOPfjPSqxt4fnZiWblxHIgeWqW8x7UqDzEtHEQLzji2cuJYQFCU6KmoJikOYAZlrTHHebjx2w==",
+ "dev": true,
+ "requires": {
+ "imurmurhash": "^0.1.4"
+ }
+ },
+ "unset-value": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/unset-value/-/unset-value-1.0.0.tgz",
+ "integrity": "sha1-g3aHP30jNRef+x5vw6jtDfyKtVk=",
+ "dev": true,
+ "requires": {
+ "has-value": "^0.3.1",
+ "isobject": "^3.0.0"
+ },
+ "dependencies": {
+ "has-value": {
+ "version": "0.3.1",
+ "resolved": "https://registry.npmjs.org/has-value/-/has-value-0.3.1.tgz",
+ "integrity": "sha1-ex9YutpiyoJ+wKIHgCVlSEWZXh8=",
+ "dev": true,
+ "requires": {
+ "get-value": "^2.0.3",
+ "has-values": "^0.1.4",
+ "isobject": "^2.0.0"
+ },
+ "dependencies": {
+ "isobject": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz",
+ "integrity": "sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk=",
+ "dev": true,
+ "requires": {
+ "isarray": "1.0.0"
+ }
+ }
+ }
+ },
+ "has-values": {
+ "version": "0.1.4",
+ "resolved": "https://registry.npmjs.org/has-values/-/has-values-0.1.4.tgz",
+ "integrity": "sha1-bWHeldkd/Km5oCCJrThL/49it3E=",
+ "dev": true
+ }
+ }
+ },
+ "upath": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/upath/-/upath-1.2.0.tgz",
+ "integrity": "sha512-aZwGpamFO61g3OlfT7OQCHqhGnW43ieH9WZeP7QxN/G/jS4jfqUkZxoryvJgVPEcrl5NL/ggHsSmLMHuH64Lhg==",
+ "dev": true,
+ "optional": true
+ },
+ "uri-js": {
+ "version": "4.4.0",
+ "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.0.tgz",
+ "integrity": "sha512-B0yRTzYdUCCn9n+F4+Gh4yIDtMQcaJsmYBDsTSG8g/OejKBodLQ2IHfN3bM7jUsRXndopT7OIXWdYqc1fjmV6g==",
+ "dev": true,
+ "requires": {
+ "punycode": "^2.1.0"
+ }
+ },
+ "urix": {
+ "version": "0.1.0",
+ "resolved": "https://registry.npmjs.org/urix/-/urix-0.1.0.tgz",
+ "integrity": "sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI=",
+ "dev": true
+ },
+ "url": {
+ "version": "0.11.0",
+ "resolved": "https://registry.npmjs.org/url/-/url-0.11.0.tgz",
+ "integrity": "sha1-ODjpfPxgUh63PFJajlW/3Z4uKPE=",
+ "dev": true,
+ "requires": {
+ "punycode": "1.3.2",
+ "querystring": "0.2.0"
+ },
+ "dependencies": {
+ "punycode": {
+ "version": "1.3.2",
+ "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.3.2.tgz",
+ "integrity": "sha1-llOgNvt8HuQjQvIyXM7v6jkmxI0=",
+ "dev": true
+ }
+ }
+ },
+ "url-join": {
+ "version": "2.0.5",
+ "resolved": "https://registry.npmjs.org/url-join/-/url-join-2.0.5.tgz",
+ "integrity": "sha1-WvIvGMBSoACkjXuCxenC4v7tpyg=",
+ "dev": true
+ },
+ "use": {
+ "version": "3.1.1",
+ "resolved": "https://registry.npmjs.org/use/-/use-3.1.1.tgz",
+ "integrity": "sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ==",
+ "dev": true
+ },
+ "util": {
+ "version": "0.11.1",
+ "resolved": "https://registry.npmjs.org/util/-/util-0.11.1.tgz",
+ "integrity": "sha512-HShAsny+zS2TZfaXxD9tYj4HQGlBezXZMZuM/S5PKLLoZkShZiGk9o5CzukI1LVHZvjdvZ2Sj1aW/Ndn2NB/HQ==",
+ "dev": true,
+ "requires": {
+ "inherits": "2.0.3"
+ },
+ "dependencies": {
+ "inherits": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz",
+ "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=",
+ "dev": true
+ }
+ }
+ },
+ "util-deprecate": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
+ "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=",
+ "dev": true
+ },
+ "v8-compile-cache": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.1.1.tgz",
+ "integrity": "sha512-8OQ9CL+VWyt3JStj7HX7/ciTL2V3Rl1Wf5OL+SNTm0yK1KvtReVulksyeRnCANHHuUxHlQig+JJDlUhBt1NQDQ==",
+ "dev": true
+ },
+ "vm-browserify": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/vm-browserify/-/vm-browserify-1.1.2.tgz",
+ "integrity": "sha512-2ham8XPWTONajOR0ohOKOHXkm3+gaBmGut3SRuu75xLd/RRaY6vqgh8NBYYk7+RW3u5AtzPQZG8F10LHkl0lAQ==",
+ "dev": true
+ },
+ "watchpack": {
+ "version": "1.7.4",
+ "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-1.7.4.tgz",
+ "integrity": "sha512-aWAgTW4MoSJzZPAicljkO1hsi1oKj/RRq/OJQh2PKI2UKL04c2Bs+MBOB+BBABHTXJpf9mCwHN7ANCvYsvY2sg==",
+ "dev": true,
+ "requires": {
+ "chokidar": "^3.4.1",
+ "graceful-fs": "^4.1.2",
+ "neo-async": "^2.5.0",
+ "watchpack-chokidar2": "^2.0.0"
+ }
+ },
+ "watchpack-chokidar2": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/watchpack-chokidar2/-/watchpack-chokidar2-2.0.0.tgz",
+ "integrity": "sha512-9TyfOyN/zLUbA288wZ8IsMZ+6cbzvsNyEzSBp6e/zkifi6xxbl8SmQ/CxQq32k8NNqrdVEVUVSEf56L4rQ/ZxA==",
+ "dev": true,
+ "optional": true,
+ "requires": {
+ "chokidar": "^2.1.8"
+ },
+ "dependencies": {
+ "anymatch": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-2.0.0.tgz",
+ "integrity": "sha512-5teOsQWABXHHBFP9y3skS5P3d/WfWXpv3FUpy+LorMrNYaT9pI4oLMQX7jzQ2KklNpGpWHzdCXTDT2Y3XGlZBw==",
+ "dev": true,
+ "optional": true,
+ "requires": {
+ "micromatch": "^3.1.4",
+ "normalize-path": "^2.1.1"
+ },
+ "dependencies": {
+ "normalize-path": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz",
+ "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=",
+ "dev": true,
+ "optional": true,
+ "requires": {
+ "remove-trailing-separator": "^1.0.1"
+ }
+ }
+ }
+ },
+ "binary-extensions": {
+ "version": "1.13.1",
+ "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-1.13.1.tgz",
+ "integrity": "sha512-Un7MIEDdUC5gNpcGDV97op1Ywk748MpHcFTHoYs6qnj1Z3j7I53VG3nwZhKzoBZmbdRNnb6WRdFlwl7tSDuZGw==",
+ "dev": true,
+ "optional": true
+ },
+ "chokidar": {
+ "version": "2.1.8",
+ "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-2.1.8.tgz",
+ "integrity": "sha512-ZmZUazfOzf0Nve7duiCKD23PFSCs4JPoYyccjUFF3aQkQadqBhfzhjkwBH2mNOG9cTBwhamM37EIsIkZw3nRgg==",
+ "dev": true,
+ "optional": true,
+ "requires": {
+ "anymatch": "^2.0.0",
+ "async-each": "^1.0.1",
+ "braces": "^2.3.2",
+ "fsevents": "^1.2.7",
+ "glob-parent": "^3.1.0",
+ "inherits": "^2.0.3",
+ "is-binary-path": "^1.0.0",
+ "is-glob": "^4.0.0",
+ "normalize-path": "^3.0.0",
+ "path-is-absolute": "^1.0.0",
+ "readdirp": "^2.2.1",
+ "upath": "^1.1.1"
+ }
+ },
+ "fsevents": {
+ "version": "1.2.13",
+ "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.13.tgz",
+ "integrity": "sha512-oWb1Z6mkHIskLzEJ/XWX0srkpkTQ7vaopMQkyaEIoq0fmtFVxOthb8cCxeT+p3ynTdkk/RZwbgG4brR5BeWECw==",
+ "dev": true,
+ "optional": true
+ },
+ "glob-parent": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-3.1.0.tgz",
+ "integrity": "sha1-nmr2KZ2NO9K9QEMIMr0RPfkGxa4=",
+ "dev": true,
+ "optional": true,
+ "requires": {
+ "is-glob": "^3.1.0",
+ "path-dirname": "^1.0.0"
+ },
+ "dependencies": {
+ "is-glob": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz",
+ "integrity": "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=",
+ "dev": true,
+ "optional": true,
+ "requires": {
+ "is-extglob": "^2.1.0"
+ }
+ }
+ }
+ },
+ "is-binary-path": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-1.0.1.tgz",
+ "integrity": "sha1-dfFmQrSA8YenEcgUFh/TpKdlWJg=",
+ "dev": true,
+ "optional": true,
+ "requires": {
+ "binary-extensions": "^1.0.0"
+ }
+ },
+ "readdirp": {
+ "version": "2.2.1",
+ "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-2.2.1.tgz",
+ "integrity": "sha512-1JU/8q+VgFZyxwrJ+SVIOsh+KywWGpds3NTqikiKpDMZWScmAYyKIgqkO+ARvNWJfXeXR1zxz7aHF4u4CyH6vQ==",
+ "dev": true,
+ "optional": true,
+ "requires": {
+ "graceful-fs": "^4.1.11",
+ "micromatch": "^3.1.10",
+ "readable-stream": "^2.0.2"
+ }
+ }
+ }
+ },
+ "webpack": {
+ "version": "4.44.2",
+ "resolved": "https://registry.npmjs.org/webpack/-/webpack-4.44.2.tgz",
+ "integrity": "sha512-6KJVGlCxYdISyurpQ0IPTklv+DULv05rs2hseIXer6D7KrUicRDLFb4IUM1S6LUAKypPM/nSiVSuv8jHu1m3/Q==",
+ "dev": true,
+ "requires": {
+ "@webassemblyjs/ast": "1.9.0",
+ "@webassemblyjs/helper-module-context": "1.9.0",
+ "@webassemblyjs/wasm-edit": "1.9.0",
+ "@webassemblyjs/wasm-parser": "1.9.0",
+ "acorn": "^6.4.1",
+ "ajv": "^6.10.2",
+ "ajv-keywords": "^3.4.1",
+ "chrome-trace-event": "^1.0.2",
+ "enhanced-resolve": "^4.3.0",
+ "eslint-scope": "^4.0.3",
+ "json-parse-better-errors": "^1.0.2",
+ "loader-runner": "^2.4.0",
+ "loader-utils": "^1.2.3",
+ "memory-fs": "^0.4.1",
+ "micromatch": "^3.1.10",
+ "mkdirp": "^0.5.3",
+ "neo-async": "^2.6.1",
+ "node-libs-browser": "^2.2.1",
+ "schema-utils": "^1.0.0",
+ "tapable": "^1.1.3",
+ "terser-webpack-plugin": "^1.4.3",
+ "watchpack": "^1.7.4",
+ "webpack-sources": "^1.4.1"
+ }
+ },
+ "webpack-cli": {
+ "version": "3.3.12",
+ "resolved": "https://registry.npmjs.org/webpack-cli/-/webpack-cli-3.3.12.tgz",
+ "integrity": "sha512-NVWBaz9k839ZH/sinurM+HcDvJOTXwSjYp1ku+5XKeOC03z8v5QitnK/x+lAxGXFyhdayoIf/GOpv85z3/xPag==",
+ "dev": true,
+ "requires": {
+ "chalk": "^2.4.2",
+ "cross-spawn": "^6.0.5",
+ "enhanced-resolve": "^4.1.1",
+ "findup-sync": "^3.0.0",
+ "global-modules": "^2.0.0",
+ "import-local": "^2.0.0",
+ "interpret": "^1.4.0",
+ "loader-utils": "^1.4.0",
+ "supports-color": "^6.1.0",
+ "v8-compile-cache": "^2.1.1",
+ "yargs": "^13.3.2"
+ }
+ },
+ "webpack-sources": {
+ "version": "1.4.3",
+ "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-1.4.3.tgz",
+ "integrity": "sha512-lgTS3Xhv1lCOKo7SA5TjKXMjpSM4sBjNV5+q2bqesbSPs5FjGmU6jjtBSkX9b4qW87vDIsCIlUPOEhbZrMdjeQ==",
+ "dev": true,
+ "requires": {
+ "source-list-map": "^2.0.0",
+ "source-map": "~0.6.1"
+ },
+ "dependencies": {
+ "source-map": {
+ "version": "0.6.1",
+ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
+ "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
+ "dev": true
+ }
+ }
+ },
+ "which": {
+ "version": "1.3.1",
+ "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz",
+ "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==",
+ "dev": true,
+ "requires": {
+ "isexe": "^2.0.0"
+ }
+ },
+ "which-module": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz",
+ "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=",
+ "dev": true
+ },
+ "worker-farm": {
+ "version": "1.7.0",
+ "resolved": "https://registry.npmjs.org/worker-farm/-/worker-farm-1.7.0.tgz",
+ "integrity": "sha512-rvw3QTZc8lAxyVrqcSGVm5yP/IJ2UcB3U0graE3LCFoZ0Yn2x4EoVSqJKdB/T5M+FLcRPjz4TDacRf3OCfNUzw==",
+ "dev": true,
+ "requires": {
+ "errno": "~0.1.7"
+ }
+ },
+ "wrap-ansi": {
+ "version": "5.1.0",
+ "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-5.1.0.tgz",
+ "integrity": "sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q==",
+ "dev": true,
+ "requires": {
+ "ansi-styles": "^3.2.0",
+ "string-width": "^3.0.0",
+ "strip-ansi": "^5.0.0"
+ }
+ },
+ "wrappy": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
+ "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=",
+ "dev": true
+ },
+ "xtend": {
+ "version": "4.0.2",
+ "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz",
+ "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==",
+ "dev": true
+ },
+ "y18n": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.0.tgz",
+ "integrity": "sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w==",
+ "dev": true
+ },
+ "yallist": {
+ "version": "3.1.1",
+ "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz",
+ "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==",
+ "dev": true
+ },
+ "yargs": {
+ "version": "13.3.2",
+ "resolved": "https://registry.npmjs.org/yargs/-/yargs-13.3.2.tgz",
+ "integrity": "sha512-AX3Zw5iPruN5ie6xGRIDgqkT+ZhnRlZMLMHAs8tg7nRruy2Nb+i5o9bwghAogtM08q1dpr2LVoS8KSTMYpWXUw==",
+ "dev": true,
+ "requires": {
+ "cliui": "^5.0.0",
+ "find-up": "^3.0.0",
+ "get-caller-file": "^2.0.1",
+ "require-directory": "^2.1.1",
+ "require-main-filename": "^2.0.0",
+ "set-blocking": "^2.0.0",
+ "string-width": "^3.0.0",
+ "which-module": "^2.0.0",
+ "y18n": "^4.0.0",
+ "yargs-parser": "^13.1.2"
+ }
+ },
+ "yargs-parser": {
+ "version": "13.1.2",
+ "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-13.1.2.tgz",
+ "integrity": "sha512-3lbsNRf/j+A4QuSZfDRA7HRSfWrzO0YjqTJd5kjAq37Zep1CEgaYmrH9Q3GwPiB9cHyd1Y1UwggGhJGoxipbzg==",
+ "dev": true,
+ "requires": {
+ "camelcase": "^5.0.0",
+ "decamelize": "^1.2.0"
+ }
+ }
+ }
+}
diff --git a/src/cobalt/demos/content/media-element-demo/package.json b/src/cobalt/demos/content/media-element-demo/package.json
new file mode 100644
index 0000000..bed93af
--- /dev/null
+++ b/src/cobalt/demos/content/media-element-demo/package.json
@@ -0,0 +1,35 @@
+{
+ "name": "media-element-demo",
+ "version": "1.0.0",
+ "main": "index.js",
+ "scripts": {
+ "start": "npm run watch & npm run server",
+ "build": "webpack",
+ "server": "http-server dist",
+ "watch": "webpack --watch"
+ },
+ "author": "",
+ "license": "ISC",
+ "devDependencies": {
+ "copy-webpack-plugin": "^6.2.1",
+ "http-server": "^0.12.3",
+ "ts-loader": "^8.0.3",
+ "typescript": "^4.0.2",
+ "webpack": "^4.44.2",
+ "webpack-cli": "^3.3.12"
+ },
+ "devDependencies-comments": {
+ "copy-webpack-plugin": "Allows webpack to copy files from public/ to dist/.",
+ "http-server": "An http server to host the site. Used as the dev server.",
+ "ts-loader": "Allows webpack to load ts files.",
+ "typescript": "The famous TypeScript.",
+ "webpack": "Bundles scripts into one file and generate dist/.",
+ "webpack-cli": "Allows us to run `webpack --watch`."
+ },
+ "dependencies": {
+ "bluebird": "^3.7.2"
+ },
+ "dependencies-comments": {
+ "bluebird": "Replaces native Promise in Cobalt because Cobalt doesn't support unhandledrejection natively."
+ }
+}
diff --git a/src/cobalt/demos/content/media-element-demo/progressive-demo.html b/src/cobalt/demos/content/media-element-demo/progressive-demo.html
deleted file mode 100644
index 2d10dde2..0000000
--- a/src/cobalt/demos/content/media-element-demo/progressive-demo.html
+++ /dev/null
@@ -1,37 +0,0 @@
-<!DOCTYPE html>
-<html>
-<head>
- <title>Progressive Demo</title>
- <style>
- body {
- background-color: rgb(255, 255, 255);
- color: #0047ab;
- font-size: 100px;
- }
- .small {
- margin: 100px;
- border: 10px solid blue;
- width: 960px;
- height: 540px;
- }
- .big {
- margin: 10px;
- border: 10px solid blue;
- width: 1280px;
- height: 720px;
- }
- </style>
-</head>
-<body>
- <div>Progressive Demo</div>
- <video autoplay loop id="v" class="small" src="progressive.mp4"></video>
- <script>
- window.setInterval(function() {
- if (document.getElementById('v').className === 'big')
- document.getElementById('v').className = 'small';
- else
- document.getElementById('v').className = 'big';
- }, 3000);
- </script>
-</body>
-</html>
diff --git a/src/cobalt/demos/content/media-element-demo/vp9_720p.webm b/src/cobalt/demos/content/media-element-demo/public/assets/vp9_720p.webm
similarity index 100%
rename from src/cobalt/demos/content/media-element-demo/vp9_720p.webm
rename to src/cobalt/demos/content/media-element-demo/public/assets/vp9_720p.webm
Binary files differ
diff --git a/src/cobalt/demos/content/media-element-demo/public/index.html b/src/cobalt/demos/content/media-element-demo/public/index.html
new file mode 100644
index 0000000..b56dfe7
--- /dev/null
+++ b/src/cobalt/demos/content/media-element-demo/public/index.html
@@ -0,0 +1,15 @@
+<!DOCTYPE html>
+<html>
+
+<head>
+ <title>Media Element Demo</title>
+ <link rel="stylesheet" type="text/css" href="styles/app.css">
+</head>
+
+<body>
+ <div id="error-logger"></div>
+ <div id="router"></div>
+ <script async type="text/javascript" src="bundle.js"></script>
+</body>
+
+</html>
diff --git a/src/cobalt/demos/content/media-element-demo/public/styles/app.css b/src/cobalt/demos/content/media-element-demo/public/styles/app.css
new file mode 100644
index 0000000..0b425ab
--- /dev/null
+++ b/src/cobalt/demos/content/media-element-demo/public/styles/app.css
@@ -0,0 +1,14 @@
+body {
+ background: #000000;
+ color: #ffffff;
+ font-size: 20px;
+}
+
+.error {
+ background:#f8d7da;
+ border-radius: .25rem;
+ border: 1px transparent solid;
+ color: #721c24;
+ margin-bottom: .25rem;
+ padding: .75rem 1.25rem;
+}
diff --git a/src/cobalt/demos/content/media-element-demo/src/components/component.ts b/src/cobalt/demos/content/media-element-demo/src/components/component.ts
new file mode 100644
index 0000000..55f9474
--- /dev/null
+++ b/src/cobalt/demos/content/media-element-demo/src/components/component.ts
@@ -0,0 +1,60 @@
+type ComponentCtor<Props> = new (props: Props) => Component<Props>;
+type ComponentFunc<Props> = (props: Props) => string;
+
+/** Base component class. */
+export class Component<Props> {
+ el!: Element;
+
+ constructor(readonly props: Props) {
+ this.props = props;
+ }
+
+ /** Lifecycle method to generate static templates. */
+ render(props: Props): string {
+ throw new Error('Must be overridden.');
+ }
+
+ /**
+ * Lifecycle method called after `render()`. It's a good opportunity to add
+ * dynamic content and add event listeners.
+ */
+ afterRender() {}
+}
+
+/** Caches the component instances hooked to DOM elements. */
+const componentMap = new WeakMap<Element, Component<unknown>>();
+
+function isComponentCtor<Props>(
+ CtorOrFunc: ComponentCtor<Props>|
+ ComponentFunc<Props>): CtorOrFunc is ComponentCtor<Props> {
+ if (CtorOrFunc.prototype instanceof Component) {
+ return true;
+ }
+ return false;
+}
+
+/**
+ * Renders a component to the container element.
+ * @param CtorOrFunc Can be either a component contructor or a component
+ * function. The component function is easier to write but does not keep
+ * track of internal states.
+ * @param props Component props.
+ * @param container The container element of the component.
+ */
+export function renderComponent<Props>(
+ CtorOrFunc: ComponentCtor<Props>|ComponentFunc<Props>, props: Props,
+ container: Element) {
+ if (!isComponentCtor(CtorOrFunc)) {
+ // Function based component
+ container.innerHTML = CtorOrFunc(props);
+ return;
+ }
+ let component = componentMap.get(container) as Component<Props>| undefined;
+ if (!(component instanceof CtorOrFunc)) {
+ component = new CtorOrFunc(props);
+ componentMap.set(container, component);
+ component.el = container;
+ }
+ container.innerHTML = component.render(props);
+ component.afterRender();
+}
diff --git a/src/cobalt/demos/content/media-element-demo/src/components/download_buffer_info.ts b/src/cobalt/demos/content/media-element-demo/src/components/download_buffer_info.ts
new file mode 100644
index 0000000..ed059d1
--- /dev/null
+++ b/src/cobalt/demos/content/media-element-demo/src/components/download_buffer_info.ts
@@ -0,0 +1,23 @@
+import {MediaDownloaderStatus} from '../utils/download_buffer';
+import {Media} from '../utils/media';
+
+interface Props {
+ mediaList: Media[];
+ reportMap: Map<Media, MediaDownloaderStatus>;
+}
+
+/** A component that displays the download buffer info. */
+export function DownloadBufferInfo({mediaList, reportMap}: Props) {
+ const elements = mediaList.map((video) => {
+ const report = reportMap.get(video);
+ if (!report) {
+ throw new Error(`Download buffer info for ${video.url} not found.`);
+ }
+ return `
+ <div>
+ ${video.url}: downloaded ${report.downloadedBytes} bytes ${
+ report.finished ? '[Done]' : ''}, queued ${report.queuedChunks} chunks.
+ </div>`;
+ });
+ return elements.join('');
+}
diff --git a/src/cobalt/demos/content/media-element-demo/src/components/error_logger.ts b/src/cobalt/demos/content/media-element-demo/src/components/error_logger.ts
new file mode 100644
index 0000000..81750dc
--- /dev/null
+++ b/src/cobalt/demos/content/media-element-demo/src/components/error_logger.ts
@@ -0,0 +1,46 @@
+import {errors} from '../utils/shared_values';
+
+import {Component} from './component';
+
+/** A component that holds error logs. */
+export class ErrorLogger extends Component<{}> {
+ /** @override */
+ render() {
+ return '';
+ }
+
+ /** @override */
+ afterRender() {
+ errors.observe((messages: string[]) => {
+ this.renderError(messages);
+ });
+ window.addEventListener('error', (message) => {
+ if (typeof message === 'string') {
+ logError(message);
+ return;
+ }
+ });
+ window.addEventListener('unhandledrejection', (evt: any) => {
+ // In cobalt where bluebird is used, the reason is under evt.detail.reason
+ const reason = evt.reason ?? evt.detail.reason;
+ logError(reason);
+ });
+ }
+
+ private renderError(messages: string[]) {
+ const elements = messages.map(message => `
+ <div class="error">${message}</div>
+ `);
+ this.el.innerHTML = elements.join('');
+ }
+}
+
+/**
+ * Logs an error message. The logged error will be automatically picked up by
+ * the error logger.
+ * @param message The error message.
+ */
+export function logError(message: string) {
+ const current = errors.get();
+ errors.set([...current, message]);
+}
diff --git a/src/cobalt/demos/content/media-element-demo/src/components/player.ts b/src/cobalt/demos/content/media-element-demo/src/components/player.ts
new file mode 100644
index 0000000..7bd9c17
--- /dev/null
+++ b/src/cobalt/demos/content/media-element-demo/src/components/player.ts
@@ -0,0 +1,240 @@
+import {DownloadBuffer} from '../utils/download_buffer';
+import {PlayMode, SwitchMode} from '../utils/enums';
+import {LimitedSourceBuffer} from '../utils/limited_source_buffer';
+import {Media} from '../utils/media';
+
+import {Component, renderComponent} from './component';
+import {DownloadBufferInfo} from './download_buffer_info';
+import {SourceBufferInfo} from './source_buffer_info';
+import {VideoInfo} from './video_info';
+
+interface Props {
+ video?: string|string[];
+ audio?: string|string[];
+ switchMode?: SwitchMode;
+}
+
+/** A component that controls video playback. */
+export class Player extends Component<Props> {
+ /** The videos to play. */
+ private readonly videos: Media[];
+
+ /** The audios to play. */
+ private readonly audios: Media[];
+
+ /** The <video> element. */
+ private videoEl!: HTMLVideoElement;
+
+ /** The element displaying video download buffer info. */
+ private videoDownloadBufferInfo!: Element;
+
+ /** The element displaying audio download buffer info. */
+ private audioDownloadBufferInfo!: Element;
+
+ /** The element displaying video source buffer info. */
+ private videoSourceBufferInfo!: Element;
+
+ /** The element displaying audio source buffer info. */
+ private audioSourceBufferInfo!: Element;
+
+ /** The element displaying video info. */
+ private videoInfo!: Element;
+
+ /**
+ * Switch mode defines whether to create a new playback session or <video>
+ * element after a media finishes playing.
+ */
+ private switchMode?: SwitchMode;
+
+ /** Play mode defines whether to play progressively or adaptively. */
+ private playMode?: PlayMode;
+
+ constructor(props: Props) {
+ super(props);
+ this.videos = convertToMediaArray(props.video);
+ this.audios = convertToMediaArray(props.audio);
+ }
+
+ /** @override */
+ render() {
+ return `
+ <div class="video-container"></div>
+ <div class="video-info"></div>
+ <div class="video-source-buffer-info"></div>
+ <div class="audio-source-buffer-info"></div>
+ <div class="video-download-buffer-info"></div>
+ <div class="audio-download-buffer-info"></div>
+ `;
+ }
+
+ /** @override */
+ async afterRender() {
+ this.videoInfo = this.el.querySelector('.video-info') as HTMLVideoElement;
+ this.videoEl = document.createElement('video');
+ this.videoEl.style.width = '1280px';
+ this.videoEl.style.height = '720px';
+ this.videoEl.addEventListener('timeupdate', () => {
+ this.renderVideoInfo();
+ });
+ this.videoEl.addEventListener('durationchange', (evt) => {
+ this.renderVideoInfo();
+ });
+ this.el.querySelector('.video-container')!.appendChild(this.videoEl);
+
+ this.videoSourceBufferInfo =
+ this.el.querySelector('.video-source-buffer-info')!;
+ this.audioSourceBufferInfo =
+ this.el.querySelector('.audio-source-buffer-info')!;
+ this.videoDownloadBufferInfo =
+ this.el.querySelector('.video-download-buffer-info')!;
+ this.audioDownloadBufferInfo =
+ this.el.querySelector('.audio-download-buffer-info')!;
+ this.play();
+ }
+
+ private renderVideoInfo() {
+ renderComponent(
+ VideoInfo, {
+ duration: this.videoEl.duration,
+ currentTime: this.videoEl.currentTime,
+ },
+ this.videoInfo);
+ }
+
+ private async play() {
+ // Do not reorder methods.
+ await this.validateParams();
+ await this.initPlayMode();
+ await this.initSwitchMode(this.props.switchMode);
+ if (this.playMode === PlayMode.PROGRESSIVE) {
+ this.playProgressiveVideo();
+ } else {
+ this.playAdaptiveVideo();
+ }
+ }
+
+ private async initSwitchMode(override?: SwitchMode) {
+ // TODO: Add support for RELOAD and RECREATE_ELEMENT.
+ this.switchMode = SwitchMode.NORMAL;
+ }
+
+ private async initPlayMode() {
+ // Because `validateProgressive_` ensures progressive videos cannot be
+ // played together with adaptive audios/videos. We can decide whether to use
+ // progressive mode by checking the type of the first videos.
+ if (this.videos.length > 0 && await this.videos[0].isProgressive()) {
+ this.playMode = PlayMode.PROGRESSIVE;
+ } else {
+ this.playMode = PlayMode.ADAPTIVE;
+ }
+ }
+
+ /**
+ * Plays all videos as progressive videos, assuming only progressive mp4
+ * videos are provided.
+ */
+ private playProgressiveVideo(videoIndex = 0) {
+ const currentMedia = this.videos[videoIndex];
+ if (!currentMedia) {
+ return;
+ }
+ this.videoEl.src = currentMedia.url;
+ const handleVideoEnd = () => {
+ this.videoEl.removeEventListener('ended', handleVideoEnd);
+ this.playProgressiveVideo(videoIndex++);
+ };
+ this.videoEl.addEventListener('ended', handleVideoEnd);
+ this.videoEl.play();
+ }
+
+ /**
+ * Plays all videos as adaptive videos.
+ * TODO: dynmaically calculate the source buffer MIME.
+ */
+ private playAdaptiveVideo() {
+ const ms = new MediaSource();
+ this.videoEl.src = URL.createObjectURL(ms);
+ ms.addEventListener('sourceopen', async () => {
+ if (this.videos.length > 0) {
+ const videoSourceBuffer =
+ ms.addSourceBuffer('video/mp4; codecs="avc1.640028"');
+ videoSourceBuffer.addEventListener('updateend', () => {
+ renderComponent(
+ SourceBufferInfo,
+ {name: 'Video', sourceBuffer: videoSourceBuffer},
+ this.videoSourceBufferInfo);
+ });
+ const downloadBuffer = new DownloadBuffer(this.videos);
+ downloadBuffer.register((reportMap) => {
+ renderComponent(
+ DownloadBufferInfo, {mediaList: this.videos, reportMap},
+ this.videoDownloadBufferInfo);
+ });
+ new LimitedSourceBuffer(
+ this.videoEl, videoSourceBuffer, this.videos, downloadBuffer);
+ }
+ if (this.audios.length > 0) {
+ const audioSourceBuffer =
+ ms.addSourceBuffer('audio/mp4; codecs="mp4a.40.2"');
+ audioSourceBuffer.addEventListener('updateend', () => {
+ renderComponent(
+ SourceBufferInfo,
+ {name: 'Audio', sourceBuffer: audioSourceBuffer},
+ this.audioSourceBufferInfo);
+ });
+ const downloadBuffer = new DownloadBuffer(this.audios);
+ downloadBuffer.register(
+ (reportMap) => {renderComponent(
+ DownloadBufferInfo, {mediaList: this.audios, reportMap},
+ this.audioDownloadBufferInfo)});
+ new LimitedSourceBuffer(
+ this.videoEl, audioSourceBuffer, this.audios, downloadBuffer);
+ }
+ });
+ this.videoEl.play();
+ }
+
+ private async validateParams() {
+ this.validateMediaExists();
+ await this.validateProgressive_();
+ }
+
+ /** Validates at least one video or audio is provided. */
+ private validateMediaExists() {
+ if (this.videos.length === 0 && this.audios.length === 0) {
+ throw new Error(
+ `No audio or video is specified. Please pass values to 'audio=' or ` +
+ `'video=' params.`);
+ }
+ }
+
+ /**
+ * Validates progressive videos are not played together with adaptive audios.
+ */
+ async validateProgressive_() {
+ let progressiveVideosCount = 0;
+ for (const video of this.videos) {
+ if (await video.isProgressive()) {
+ progressiveVideosCount++;
+ }
+ }
+ if (progressiveVideosCount > 0 &&
+ (progressiveVideosCount !== this.videos.length ||
+ this.audios.length > 0)) {
+ throw new Error(
+ 'Progressive video[s] cannot be played together with adaptive ' +
+ 'video[s] and audio[s]');
+ }
+ }
+}
+
+/** Converts filenames to a list of media. */
+function convertToMediaArray(filenames?: string|string[]): Media[] {
+ if (!filenames) {
+ return [];
+ }
+ if (!Array.isArray(filenames)) {
+ return [new Media(filenames)];
+ }
+ return filenames.map(filename => new Media(filename));
+}
diff --git a/src/cobalt/demos/content/media-element-demo/src/components/router.ts b/src/cobalt/demos/content/media-element-demo/src/components/router.ts
new file mode 100644
index 0000000..11e3d75
--- /dev/null
+++ b/src/cobalt/demos/content/media-element-demo/src/components/router.ts
@@ -0,0 +1,41 @@
+import {Component, renderComponent} from './component';
+
+import {Watch} from './watch';
+
+/** A component that parses URL params and decide what page to load. */
+export class Router extends Component<{}> {
+ /** @override */
+ render() {
+ return `<div class="router-content"></div>`;
+ }
+
+ /** @override */
+ afterRender() {
+ const params = parseParams();
+ renderComponent(Watch, params, this.el.querySelector('.router-content')!);
+ }
+}
+
+/**
+ * Converts the GET params to an object.
+ * @return The parsed params object.
+ */
+function parseParams(): Record<string, string|string[]> {
+ const params: Record<string, string|string[]> = {};
+ if (!location.search) {
+ return params;
+ }
+ const terms = location.search.slice(1).split('&');
+ for (const term of terms) {
+ const [key, value] = term.split('=');
+ if (params[key] !== undefined) {
+ throw new Error(`Detected multiple values for ${key}`);
+ }
+ if (value.includes(',')) {
+ params[key] = value.split(',');
+ } else {
+ params[key] = value;
+ }
+ }
+ return params;
+}
diff --git a/src/cobalt/demos/content/media-element-demo/src/components/source_buffer_info.ts b/src/cobalt/demos/content/media-element-demo/src/components/source_buffer_info.ts
new file mode 100644
index 0000000..92343f3
--- /dev/null
+++ b/src/cobalt/demos/content/media-element-demo/src/components/source_buffer_info.ts
@@ -0,0 +1,9 @@
+interface Props {
+ sourceBuffer: SourceBuffer;
+ name: string;
+}
+
+/** A component that displays the source buffer info. */
+export function SourceBufferInfo({sourceBuffer, name}: Props) {
+ return `<div>${name} buffered: ${sourceBuffer.buffered.end(0)} sec</div>`;
+}
diff --git a/src/cobalt/demos/content/media-element-demo/src/components/video_info.ts b/src/cobalt/demos/content/media-element-demo/src/components/video_info.ts
new file mode 100644
index 0000000..3f8306f
--- /dev/null
+++ b/src/cobalt/demos/content/media-element-demo/src/components/video_info.ts
@@ -0,0 +1,9 @@
+interface Props {
+ duration: number;
+ currentTime: number;
+}
+
+/** A component that displays video info. */
+export function VideoInfo({duration, currentTime}: Props) {
+ return `<div>${currentTime} / ${duration}</div>`;
+}
diff --git a/src/cobalt/demos/content/media-element-demo/src/components/watch.ts b/src/cobalt/demos/content/media-element-demo/src/components/watch.ts
new file mode 100644
index 0000000..5503d44
--- /dev/null
+++ b/src/cobalt/demos/content/media-element-demo/src/components/watch.ts
@@ -0,0 +1,45 @@
+import {isCobalt} from '../utils/shared_values';
+import {Component, renderComponent} from './component';
+import {Player} from './player';
+
+/** TODO: Add correct watch props. */
+interface Props {}
+
+/** The watch page. */
+export class Watch extends Component<Props> {
+ /** @override */
+ render() {
+ return '<div class="player"></div>';
+ }
+
+ /** @override */
+ afterRender() {
+ // Mainstream browsers require users to interact with the document first
+ // before it can start play any video. This rule does not apply to Cobalt.
+ if (isCobalt) {
+ this.boostrapPage();
+ } else {
+ this.waitForInteraction();
+ }
+ }
+
+ /**
+ * Listens to any key event and displays a message. Bootstraps the page once
+ * user interacts with the docuemnt.
+ */
+ private waitForInteraction() {
+ const messageEl = document.createElement('h1');
+ messageEl.textContent = 'Press ANY KEY to start';
+ this.el.appendChild(messageEl);
+ const handler = () => {
+ window.removeEventListener('keyup', handler);
+ messageEl.parentElement!.removeChild(messageEl);
+ this.boostrapPage();
+ };
+ window.addEventListener('keyup', handler);
+ }
+
+ private boostrapPage() {
+ renderComponent(Player, this.props, this.el.querySelector('.player')!);
+ }
+}
diff --git a/src/cobalt/demos/content/media-element-demo/src/index.ts b/src/cobalt/demos/content/media-element-demo/src/index.ts
new file mode 100644
index 0000000..0554019
--- /dev/null
+++ b/src/cobalt/demos/content/media-element-demo/src/index.ts
@@ -0,0 +1,15 @@
+import * as Promise from 'bluebird';
+
+import {renderComponent} from './components/component';
+import {ErrorLogger} from './components/error_logger';
+import {Router} from './components/router';
+import {isCobalt} from './utils/shared_values';
+
+if (isCobalt) {
+ // Use bluebird as the default promise because Cobalt does not support
+ // unhandledrejection natively.
+ window.Promise = Promise as any;
+}
+
+renderComponent(ErrorLogger, {}, document.querySelector('#error-logger')!);
+renderComponent(Router, {}, document.querySelector('#router')!);
diff --git a/src/cobalt/demos/content/media-element-demo/src/utils/download_buffer.ts b/src/cobalt/demos/content/media-element-demo/src/utils/download_buffer.ts
new file mode 100644
index 0000000..8cbb218
--- /dev/null
+++ b/src/cobalt/demos/content/media-element-demo/src/utils/download_buffer.ts
@@ -0,0 +1,187 @@
+import {download} from './downloader';
+import {Media} from './media';
+
+const CHUNK_SIZE = 1024 * 1024; // 1MB
+const DOWNLOAD_BUFFER_MAX_SIZE = 10;
+
+type DownloadBufferListener = (results: Map<Media, MediaDownloaderStatus>) =>
+ void;
+
+/**
+ * Download buffer fetches the passed in media list chunk by chunk. It
+ * automatically pauses the download when the buffer reaches the limit and
+ * resumes when a chunk is taken out from the buffer.
+ */
+export class DownloadBuffer {
+ private isDownloading = false;
+ private currentMediaIndex = 0;
+ private listeners: DownloadBufferListener[] = [];
+ private downloaderMap = new Map<Media, MediaDownloader>();
+
+ constructor(
+ private readonly mediaList: Media[],
+ private readonly limit = DOWNLOAD_BUFFER_MAX_SIZE) {
+ for (const media of mediaList) {
+ this.downloaderMap.set(media, new MediaDownloader(media));
+ }
+ this.download();
+ }
+
+ /** Registers callback to listen to download buffer changes. */
+ register(callback: DownloadBufferListener) {
+ this.listeners.push(callback);
+ return () => {
+ const index = this.listeners.indexOf(callback);
+ if (index !== -1) {
+ this.listeners.splice(index, 1);
+ }
+ }
+ }
+
+ /** Calls listeners with the current media downloaders' status. */
+ private reportChanges() {
+ const result = new Map<Media, MediaDownloaderStatus>();
+ this.downloaderMap.forEach((downloader) => {
+ result.set(downloader.media, downloader.status());
+ });
+ for (const listener of this.listeners) {
+ listener(result);
+ }
+ }
+
+ /** @return The total buffer sizes of all media. */
+ size() {
+ let res = 0;
+ this.downloaderMap.forEach((downloader) => {
+ res += downloader.size();
+ });
+ return res;
+ }
+
+ private async download() {
+ if (this.isDownloading) {
+ return;
+ }
+ const media = this.mediaList[this.currentMediaIndex];
+ if (!media) {
+ // All media are processed.
+ return;
+ }
+ const downloader = this.downloaderMap.get(media);
+ if (!downloader) {
+ throw new Error(
+ `${media.url} does not have a downloader. This should not happen.`);
+ }
+ if (downloader.downloadFinished()) {
+ // The current media has finished downloading. Move on to the next one.
+ this.currentMediaIndex++;
+ this.download();
+ return;
+ }
+ this.isDownloading = true;
+ await downloader.downloadAndEnqueueNextChunk();
+ this.isDownloading = false;
+ this.reportChanges();
+ if (this.size() < this.limit) {
+ this.download();
+ }
+ }
+
+ /** Shifts a chunk of the requested media. */
+ shift(media: Media) {
+ return new Promise<ArrayBuffer|undefined>((resolve, reject) => {
+ const downloader = this.downloaderMap.get(media);
+ if (!downloader) {
+ throw new Error(
+ `${media.url} does not have a downloader. This should not happen.`);
+ }
+ const chunk = downloader.shift();
+ if (chunk) {
+ this.reportChanges();
+ this.download();
+ resolve(chunk);
+ return;
+ }
+ if (downloader.downloadFinished()) {
+ resolve();
+ return;
+ }
+ // The request media has not been downloaded. Wait until it is ready.
+ downloader.registerOnce(() => {
+ const chunk = downloader.shift();
+ if (chunk) {
+ this.reportChanges();
+ this.download();
+ resolve(chunk);
+ } else {
+ reject(new Error('Something is wrong'));
+ }
+ });
+ });
+ }
+}
+
+export interface MediaDownloaderStatus {
+ downloadedBytes: number;
+ queuedChunks: number;
+ finished: boolean;
+}
+
+/** Controls how to download a media. */
+class MediaDownloader {
+ private finished = false;
+ private chunks: ArrayBuffer[] = [];
+ private startingByte = 0;
+ private listeners: Array<() => void> = [];
+
+ constructor(readonly media: Media) {}
+
+ status(): MediaDownloaderStatus {
+ return {
+ downloadedBytes: this.startingByte,
+ queuedChunks: this.size(),
+ finished: this.downloadFinished(),
+ };
+ }
+
+ size() {
+ return this.chunks.length;
+ }
+
+ /**
+ * Listens when a chunk is enqueued. The callback will only be triggered
+ * once.
+ */
+ registerOnce(callback: () => void) {
+ this.listeners.push(callback);
+ }
+
+ downloadFinished(): boolean {
+ return this.finished;
+ }
+
+ shift(): ArrayBuffer|undefined {
+ return this.chunks.shift();
+ }
+
+ /** Downloads next chunk and enqueues the chunk to the buffer. */
+ async downloadAndEnqueueNextChunk() {
+ if (this.finished) {
+ throw new Error(`Attempt to download ${
+ this.media.url} after it has finished downloading.`);
+ }
+ const data = await download(
+ this.media.url, this.startingByte, this.startingByte + CHUNK_SIZE - 1);
+ if (data.byteLength === 0) {
+ console.log(`${this.media.url} is fully downloaded.`);
+ this.finished = true;
+ return;
+ }
+ console.log(`Downloaded ${this.media.url} at ${this.startingByte}`);
+ this.startingByte += data.byteLength;
+ this.chunks.push(data);
+ while (this.listeners.length > 0) {
+ this.listeners.shift()!();
+ }
+ }
+}
diff --git a/src/cobalt/demos/content/media-element-demo/src/utils/downloader.ts b/src/cobalt/demos/content/media-element-demo/src/utils/downloader.ts
new file mode 100644
index 0000000..8d2cc96
--- /dev/null
+++ b/src/cobalt/demos/content/media-element-demo/src/utils/downloader.ts
@@ -0,0 +1,20 @@
+import {logError} from '../components/error_logger';
+
+/**
+ * Downloads an asset with the provided URL.
+ * @param url Asset path.
+ * @param begin Start byte.
+ * @param end End byte.
+ */
+export async function download(
+ url: string, begin: number, end: number): Promise<ArrayBuffer> {
+ const response = await fetch(url, {
+ headers: {
+ 'Range': `bytes=${begin}-${end}`,
+ },
+ });
+ if (response.status === 404) {
+ logError(`${url} does not exist.`);
+ }
+ return response.arrayBuffer();
+}
diff --git a/src/cobalt/demos/content/media-element-demo/src/utils/enums.ts b/src/cobalt/demos/content/media-element-demo/src/utils/enums.ts
new file mode 100644
index 0000000..3877882
--- /dev/null
+++ b/src/cobalt/demos/content/media-element-demo/src/utils/enums.ts
@@ -0,0 +1,16 @@
+/** A player config defines how to switch between videos. */
+export enum SwitchMode {
+ // Play adaptive videos under the same playback session using one media
+ // source. Play under different playback sessions if adaptive playback is not
+ // possible.
+ NORMAL = 'normal',
+ // Play adaptive videos under different playback sessions.
+ RELOAD = 'reload',
+ // Use a new video element when switching to the next media file.
+ RECREATE_ELEMENT = 'recreate-element',
+}
+
+export enum PlayMode {
+ PROGRESSIVE = 'progressive',
+ ADAPTIVE = 'adaptive',
+}
diff --git a/src/cobalt/demos/content/media-element-demo/src/utils/limited_source_buffer.ts b/src/cobalt/demos/content/media-element-demo/src/utils/limited_source_buffer.ts
new file mode 100644
index 0000000..63f5aae
--- /dev/null
+++ b/src/cobalt/demos/content/media-element-demo/src/utils/limited_source_buffer.ts
@@ -0,0 +1,87 @@
+import {DownloadBuffer} from './download_buffer';
+import {Media} from './media';
+
+const UNPLAYED_BUFFER_MAX_SIZE = 10; // Only buffer 10 seconds maximum.
+
+/**
+ * A source buffer wrapper that limits the array buffers that can be added to
+ * the source buffer. If the bufferred length exceeds the limit, it will
+ * automatically pauses and waits until the remaining playback time is below the
+ * limit.
+ */
+export class LimitedSourceBuffer {
+ private scheduleTimeoutId = -1;
+ private currentMediaIndex = 0;
+
+ constructor(
+ private readonly videoEl: HTMLVideoElement,
+ private readonly sourceBuffer: SourceBuffer,
+ private readonly mediaList: Media[],
+ private readonly downloadBuffer: DownloadBuffer) {
+ this.appendNext();
+ }
+
+ /** Appends the next array buffer to the source buffer. */
+ async appendNext() {
+ const unplayedBufferLength = this.unplayedBufferLength();
+ if (unplayedBufferLength > UNPLAYED_BUFFER_MAX_SIZE) {
+ // Buffered too many content. Wait until we need to add buffer again.
+ const timeout = unplayedBufferLength - UNPLAYED_BUFFER_MAX_SIZE;
+ clearTimeout(this.scheduleTimeoutId);
+ console.log(`Schedule appendNext in ${timeout} sec.`);
+ this.scheduleTimeoutId =
+ setTimeout(() => this.appendNext(), timeout * 1000);
+ return;
+ }
+ const media = this.mediaList[this.currentMediaIndex];
+ if (!media) {
+ // All media are appended.
+ console.log('All media are appended');
+ return;
+ }
+ const chunk = await this.downloadBuffer.shift(media);
+ if (!chunk) {
+ // No more buffer left to append in the current media. Move on to the next
+ // one.
+ console.log(`${media.url} finished appending. Move on to the next one.`);
+ this.currentMediaIndex++;
+ const bufferedLength = this.sourceBuffer.buffered.end(0);
+ this.sourceBuffer.timestampOffset = bufferedLength;
+ this.appendNext();
+ return;
+ }
+ console.log(`Appending new chunk from ${media.url}`);
+ await this.appendChunkToBuffer(chunk);
+ this.appendNext();
+ }
+
+ /**
+ * Appends a chunk to the source buffer. Waits until the update is completed.
+ */
+ private async appendChunkToBuffer(chunk: ArrayBuffer) {
+ return new Promise((resolve, reject) => {
+ this.sourceBuffer.appendBuffer(chunk);
+ const unsubscribe = () => {
+ this.sourceBuffer.removeEventListener('updateend', onupdateend);
+ this.sourceBuffer.removeEventListener('error', onerror);
+ };
+ const onerror = () => {
+ unsubscribe();
+ reject(new Error('Append to buffer failed.'));
+ };
+ const onupdateend = () => {
+ unsubscribe();
+ resolve();
+ };
+ this.sourceBuffer.addEventListener('updateend', onupdateend);
+ this.sourceBuffer.addEventListener('error', onerror);
+ });
+ }
+
+ private unplayedBufferLength() {
+ if (this.sourceBuffer.buffered.length === 0) {
+ return 0;
+ }
+ return this.sourceBuffer.buffered.end(0) - this.videoEl.currentTime;
+ }
+}
diff --git a/src/cobalt/demos/content/media-element-demo/src/utils/media.ts b/src/cobalt/demos/content/media-element-demo/src/utils/media.ts
new file mode 100644
index 0000000..5502b56
--- /dev/null
+++ b/src/cobalt/demos/content/media-element-demo/src/utils/media.ts
@@ -0,0 +1,84 @@
+import {logError} from '../components/error_logger';
+
+import {download} from './downloader';
+
+/** A class that holds media metadata. */
+export class Media {
+ readonly url: string;
+ private metadata?: MediaMetadata;
+
+ constructor(filename: string) {
+ /** @type {string} Asset url. */
+ this.url = `assets/${filename}`;
+ }
+
+ async getMetadata(): Promise<MediaMetadata> {
+ if (!this.metadata) {
+ this.metadata = await this.fetchMetadata();
+ }
+ return this.metadata;
+ }
+
+ /**
+ * @return Whether the video is a progressive video.
+ */
+ async isProgressive(): Promise<boolean> {
+ const metadata = await this.getMetadata();
+ return metadata.type === 'mp42';
+ }
+
+ /** Downloads the head and builds metadata. */
+ private async fetchMetadata(): Promise<MediaMetadata> {
+ if (this.url.substr(-3) !== 'mp4') {
+ // TODO: Add more media type support.
+ return {};
+ }
+ // Metadata should be included in the first 10K.
+ const buffer = await download(this.url, 0, 1024 * 10);
+ if (buffer.byteLength === 0) {
+ return {};
+ }
+ const headBuffer = buffer.slice(0, getSize(buffer));
+ const type = getFtypType(headBuffer);
+ return {
+ type,
+ };
+ }
+}
+
+interface MediaMetadata {
+ /** The ftyp type. */
+ type?: string;
+}
+
+/**
+ * Gets the buffer size from the first 4 bytes.
+ * @return Buffer size.
+ */
+function getSize(buffer: ArrayBuffer): number {
+ const dv = new DataView(buffer.slice(0, 4));
+ return dv.getUint32(0);
+}
+
+/**
+ * Turns the buffer into a string.
+ * @return The generated string.
+ */
+function stringifyBuffer(
+ buffer: ArrayBuffer, begin: number, end: number): string {
+ return String.fromCharCode.apply(
+ null, Array.from(new Uint8Array(buffer.slice(begin, end))));
+}
+
+/**
+ * Gets the ftyp type from the buffer.
+ * @return The ftyp type. Undefined if there is an error.
+ */
+function getFtypType(buffer: ArrayBuffer): string|undefined {
+ const code = stringifyBuffer(buffer, 4, 8);
+ if (code !== 'ftyp') {
+ logError(`unknown type code ${code}`);
+ return;
+ }
+ return stringifyBuffer(buffer, 8, 12);
+}
diff --git a/src/cobalt/demos/content/media-element-demo/src/utils/observable.ts b/src/cobalt/demos/content/media-element-demo/src/utils/observable.ts
new file mode 100644
index 0000000..63c451f
--- /dev/null
+++ b/src/cobalt/demos/content/media-element-demo/src/utils/observable.ts
@@ -0,0 +1,50 @@
+type ObservableCallback<T> = (next: T, prev: T) => void;
+
+/**
+ * An observable value. Observers can attach a callback that gets called when
+ * the value changes.
+ */
+export class Observable<T> {
+ /** The actual value. */
+ private value: T;
+
+ /** Callbacks to trigger when the value changes. */
+ private callbacks: Array<ObservableCallback<T>> = [];
+
+ constructor(initValue: T) {
+ this.value = initValue;
+ }
+
+ /**
+ * Sets a new value and triggers the observer callbacks if the value changes.
+ */
+ set(value: T) {
+ if (this.value === value) {
+ return;
+ }
+
+ const oldValue = value;
+ this.value = value;
+ for (const callback of this.callbacks) {
+ callback(this.value, oldValue);
+ }
+ }
+
+ get(): T {
+ return this.value;
+ }
+
+ /**
+ * Triggers the callback on value changes.
+ * @return The unsubscriber.
+ */
+ observe(callback: ObservableCallback<T>): () => void {
+ this.callbacks.push(callback);
+ return () => {
+ const index = this.callbacks.indexOf(callback);
+ if (index !== -1) {
+ this.callbacks.splice(index, 1);
+ }
+ }
+ }
+}
diff --git a/src/cobalt/demos/content/media-element-demo/src/utils/shared_values.ts b/src/cobalt/demos/content/media-element-demo/src/utils/shared_values.ts
new file mode 100644
index 0000000..031b96c
--- /dev/null
+++ b/src/cobalt/demos/content/media-element-demo/src/utils/shared_values.ts
@@ -0,0 +1,5 @@
+/** This file contains singleton values shared by the application. */
+import {Observable} from './observable';
+
+export const errors = new Observable<string[]>([]);
+export const isCobalt = navigator.userAgent.indexOf('Cobalt') >= 0;
diff --git a/src/cobalt/demos/content/media-element-demo/tsconfig.json b/src/cobalt/demos/content/media-element-demo/tsconfig.json
new file mode 100644
index 0000000..afc9053
--- /dev/null
+++ b/src/cobalt/demos/content/media-element-demo/tsconfig.json
@@ -0,0 +1,15 @@
+{
+ "compilerOptions": {
+ "outDir": "./dist/",
+ "sourceMap": true,
+ "noImplicitAny": true,
+ "module": "es6",
+ "target": "es5",
+ "allowJs": true,
+ "strict": true,
+ "lib": [
+ "esnext",
+ "dom"
+ ],
+ }
+}
diff --git a/src/cobalt/demos/content/media-element-demo/webpack.config.js b/src/cobalt/demos/content/media-element-demo/webpack.config.js
new file mode 100644
index 0000000..ab9687c
--- /dev/null
+++ b/src/cobalt/demos/content/media-element-demo/webpack.config.js
@@ -0,0 +1,29 @@
+const path = require('path');
+const CopyPlugin = require('copy-webpack-plugin');
+
+module.exports = {
+ mode: 'development',
+ devtool: 'source-map',
+ module: {
+ rules: [{
+ test: /\.ts$/,
+ use: 'ts-loader',
+ exclude: /node_modules/,
+ }]
+ },
+ resolve: {
+ extensions: ['.ts', '.js'],
+ },
+ entry: './src/index.ts',
+ output: {
+ path: path.resolve(__dirname, 'dist'),
+ filename: 'bundle.js',
+ },
+ plugins: [
+ new CopyPlugin({
+ patterns: [
+ {from: 'public'},
+ ]
+ }),
+ ]
+};
diff --git a/src/cobalt/doc/splash_screen.md b/src/cobalt/doc/splash_screen.md
index 9122555..fbb6b6d 100644
--- a/src/cobalt/doc/splash_screen.md
+++ b/src/cobalt/doc/splash_screen.md
@@ -49,15 +49,15 @@
first time.
3. **Build-time fallback splash screen:** If a web cached splash screen is
- unavailable and command line parameters are not passed by the system, a
- `gyp_configuration.gypi` fallback splash screen may be used. Porters should
- set the gypi variable `fallback_splash_screen_url` to the splash screen
- URL.
+ unavailable and command line parameters are not passed by the system,
+ a CobaltExtensionConfigurationApi fallback splash screen may be used.
+ Porters should set the `CobaltFallbackSplashScreenUrl` value in
+ `configuration.cc` to the splash screen URL.
- 4. **Default splash screen:** If no web cached splash screen is
- available, and command line and `gyp_configuration.gypi` fallbacks are not
- set, a default splash screen will be used. This is set in `base.gypi` via
- `fallback_splash_screen_url%` to refer to a black splash screen.
+ 4. **Default splash screen:** If no web cached splash screen is available, and
+ command line and CobaltExtensionConfigurationApi fallbacks are not set, a
+ default splash screen will be used. This is set in
+ `configuration_defaults.cc` to refer to a black splash screen.
## Web-updatability
@@ -85,6 +85,40 @@
Cobalt will also need to read the cached splash screen from the cache directory
when starting up.
+## Topic-specific splash screens
+
+It is possible to specify multiple splash screens for a given Cobalt-based
+application, using a start-up 'topic' to select between the available splash
+screens. This can be useful when an application has multiple entry points that
+require different splash screens. The topic may be specified in the start-up url
+or deeplink as a query parameter. For example,
+`https://www.example.com/path?topic=foo`. If a splash-screen has been specified
+for topic 'foo', it will be used. Otherwise, the topic is ignored. Topic values
+should be URL encoded and limited to alphanumeric characters, hyphens,
+underscores, and percent signs.
+
+There are three ways to specify topic-specific splash screens. These methods mirror
+the types of splash screens listed above, and unless specified, the rules here
+are the same as for non-topic-based splash screens.
+
+ 1. **Web cached splash screen:** A custom `rel="<topic>_splashscreen"`
+ attribute on a link element is used to specify a topic-specific splash
+ screen. There can be any number of these elements with different topics, in
+ addition to the topic-neutral `rel="splashscreen"`.
+
+ 2. **Command line fallback splash screen:** The command line argument
+ `--fallback_splash_screen_topics` can be used if the cache is unavailable.
+ The argument accepts a list of topic/file parameters. If a file is not a
+ valid URL path, then it will be used as a filename at the path specified by
+ `--fallback_splash_screen_url`. For example,
+ `foo_topic=file:///foo.html&bar=bar.html`.
+
+ 3. **Build-time fallback splash screen:** If a web cached splash screen is
+ unavailable and command line parameters are not passed by the system, a
+ CobaltExtensionConfigurationApi fallback splash screen may be used. Porters
+ should set the `CobaltFallbackSplashScreenTopics` value in
+ `configuration.cc` and this value should look like the command line option.
+
## Application-specific splash screens
On systems that plan to support multiple Cobalt-based applications, an
@@ -94,9 +128,8 @@
the Cobalt binary must be handled by the system.
Alternatively, an application developer may use the default black splash screen
-specified in base.gypi whenever a cached splash screen is not available and rely
-on the web application to specify an application-specific cached splash screen
-otherwise.
+whenever a cached splash screen is not available and rely on the web application
+to specify an application-specific cached splash screen otherwise.
## Provided embedded resource splash screens
For convenience, we currently provide the following splash screens as embedded
diff --git a/src/cobalt/dom/custom_event_test.cc b/src/cobalt/dom/custom_event_test.cc
index ee0b08f..083c08f 100644
--- a/src/cobalt/dom/custom_event_test.cc
+++ b/src/cobalt/dom/custom_event_test.cc
@@ -31,7 +31,6 @@
#include "cobalt/dom_parser/parser.h"
#include "cobalt/loader/fetcher_factory.h"
#include "cobalt/loader/loader_factory.h"
-#include "cobalt/media_session/media_session.h"
#include "cobalt/script/global_environment.h"
#include "cobalt/script/javascript_engine.h"
#include "cobalt/script/source_code.h"
@@ -84,7 +83,7 @@
kCspEnforcementEnable, base::Closure() /* csp_policy_changed */,
base::Closure() /* ran_animation_frame_callbacks */,
dom::Window::CloseCallback() /* window_close */,
- base::Closure() /* window_minimize */, NULL, NULL, NULL,
+ base::Closure() /* window_minimize */, NULL, NULL,
dom::Window::OnStartDispatchEventCallback(),
dom::Window::OnStopDispatchEventCallback(),
dom::ScreenshotManager::ProvideScreenshotFunctionCallback(), NULL);
diff --git a/src/cobalt/dom/error_event_test.cc b/src/cobalt/dom/error_event_test.cc
index 937cd45..7f431a7 100644
--- a/src/cobalt/dom/error_event_test.cc
+++ b/src/cobalt/dom/error_event_test.cc
@@ -31,7 +31,6 @@
#include "cobalt/dom_parser/parser.h"
#include "cobalt/loader/fetcher_factory.h"
#include "cobalt/loader/loader_factory.h"
-#include "cobalt/media_session/media_session.h"
#include "cobalt/script/global_environment.h"
#include "cobalt/script/javascript_engine.h"
#include "cobalt/script/source_code.h"
@@ -86,7 +85,7 @@
kCspEnforcementEnable, base::Closure() /* csp_policy_changed */,
base::Closure() /* ran_animation_frame_callbacks */,
dom::Window::CloseCallback() /* window_close */,
- base::Closure() /* window_minimize */, NULL, NULL, NULL,
+ base::Closure() /* window_minimize */, NULL, NULL,
dom::Window::OnStartDispatchEventCallback(),
dom::Window::OnStopDispatchEventCallback(),
dom::ScreenshotManager::ProvideScreenshotFunctionCallback(), NULL);
diff --git a/src/cobalt/dom/html_element.cc b/src/cobalt/dom/html_element.cc
index 1db3c22..e3f92a6 100644
--- a/src/cobalt/dom/html_element.cc
+++ b/src/cobalt/dom/html_element.cc
@@ -17,6 +17,7 @@
#include <algorithm>
#include <map>
#include <memory>
+#include <utility>
#include "base/lazy_instance.h"
#include "base/message_loop/message_loop_task_runner.h"
@@ -1032,7 +1033,6 @@
// themselves still need to have their computed style updated, in case the
// value of display is changed.
if (computed_style()->display() == cssom::KeywordValue::GetNone()) {
- ReleaseUiNavigationItem();
return;
}
@@ -1079,6 +1079,7 @@
}
}
+ ReleaseUiNavigationItem();
MarkNotDisplayedOnDescendants();
}
@@ -1521,8 +1522,7 @@
if (property == U_LEFT_TO_RIGHT) {
return HTMLElement::kDirLeftToRight;
}
- if (property == U_RIGHT_TO_LEFT ||
- property == U_RIGHT_TO_LEFT_ARABIC) {
+ if (property == U_RIGHT_TO_LEFT || property == U_RIGHT_TO_LEFT_ARABIC) {
return HTMLElement::kDirRightToLeft;
}
}
@@ -1615,11 +1615,11 @@
return kDirLeftToRight;
}
- // Although the spec says to use the parent's directionality, the W3C test
- // (the-dir-attribute-069.html) says to default to LTR. Chrome follows the
- // W3C expectation, so follow Chrome. Additional discussion here:
- // https://github.com/w3c/i18n-drafts/issues/235
- // The following code block which implements the spec is left for reference.
+// Although the spec says to use the parent's directionality, the W3C test
+// (the-dir-attribute-069.html) says to default to LTR. Chrome follows the
+// W3C expectation, so follow Chrome. Additional discussion here:
+// https://github.com/w3c/i18n-drafts/issues/235
+// The following code block which implements the spec is left for reference.
#if 0
// Otherwise, the directionality of the element is the same as the element's
// parent element's directionality.
@@ -2106,8 +2106,7 @@
element = element->next_element_sibling()) {
HTMLElement* html_element = element->AsHTMLElement();
if (html_element) {
- HTMLMediaElement* media_html_element =
- html_element->AsHTMLMediaElement();
+ HTMLMediaElement* media_html_element = html_element->AsHTMLMediaElement();
if (media_html_element) {
html_media_elements->push_back(media_html_element);
}
@@ -2160,7 +2159,7 @@
ui_nav_item_type = ui_navigation::kNativeItemTypeContainer;
}
- if (ui_nav_item_type) {
+ if (ui_nav_item_type && IsDisplayed()) {
ui_navigation::NativeItemDir ui_nav_item_dir;
ui_nav_item_dir.is_left_to_right =
directionality() == kLeftToRightDirectionality;
@@ -2175,12 +2174,7 @@
// The current navigation item isn't of the correct type. Disable it so
// that callbacks won't be invoked for it. The object will be destroyed
// when all references to it are released.
- if (g_ui_nav_focus_ == this) {
- g_ui_nav_focus_ = nullptr;
- ui_nav_item_->UnfocusAll();
- }
- ui_nav_item_->SetEnabled(false);
- ui_nav_item_ = nullptr;
+ ReleaseUiNavigationItem();
}
ui_nav_item_ = new ui_navigation::NavItem(
@@ -2204,12 +2198,7 @@
return false;
} else if (ui_nav_item_) {
// This navigation item is no longer relevant.
- if (g_ui_nav_focus_ == this) {
- g_ui_nav_focus_ = nullptr;
- ui_nav_item_->UnfocusAll();
- }
- ui_nav_item_->SetEnabled(false);
- ui_nav_item_ = nullptr;
+ ReleaseUiNavigationItem();
return false;
}
@@ -2218,13 +2207,6 @@
void HTMLElement::ReleaseUiNavigationItem() {
if (ui_nav_item_) {
- // Make sure layout updates this element.
- InvalidateLayoutBoxesOfNodeAndAncestors();
- if (ui_nav_item_->IsContainer()) {
- // Make sure layout updates any focus items that may be in this container.
- InvalidateLayoutBoxesOfDescendants();
- }
-
// Disable the UI navigation item so it won't receive anymore callbacks
// while being released.
if (g_ui_nav_focus_ == this) {
diff --git a/src/cobalt/dom/navigator.cc b/src/cobalt/dom/navigator.cc
index a6d3ce3..8b8d5f6 100644
--- a/src/cobalt/dom/navigator.cc
+++ b/src/cobalt/dom/navigator.cc
@@ -145,14 +145,13 @@
Navigator::Navigator(
script::EnvironmentSettings* settings, const std::string& user_agent,
- const std::string& language, scoped_refptr<MediaSession> media_session,
+ const std::string& language,
scoped_refptr<cobalt::dom::captions::SystemCaptionSettings> captions,
script::ScriptValueFactory* script_value_factory)
: user_agent_(user_agent),
language_(language),
mime_types_(new MimeTypeArray()),
plugins_(new PluginArray()),
- media_session_(media_session),
media_devices_(
new media_capture::MediaDevices(settings, script_value_factory)),
system_caption_settings_(captions),
@@ -223,8 +222,20 @@
return plugins_;
}
-const scoped_refptr<media_session::MediaSession>& Navigator::media_session()
- const {
+const scoped_refptr<media_session::MediaSession>& Navigator::media_session() {
+ if (media_session_ == nullptr) {
+ media_session_ =
+ scoped_refptr<media_session::MediaSession>(new MediaSession());
+
+ if (media_player_factory_ != nullptr) {
+ media_session_->EnsureMediaSessionClient();
+ DCHECK(media_session_->media_session_client());
+ media_session_->media_session_client()
+ ->SetMaybeFreezeCallback(maybe_freeze_callback_);
+ media_session_->media_session_client()
+ ->SetMediaPlayerFactory(media_player_factory_);
+ }
+ }
return media_session_;
}
diff --git a/src/cobalt/dom/navigator.h b/src/cobalt/dom/navigator.h
index 1489f78..348f624 100644
--- a/src/cobalt/dom/navigator.h
+++ b/src/cobalt/dom/navigator.h
@@ -23,6 +23,7 @@
#include "cobalt/dom/eme/media_key_system_configuration.h"
#include "cobalt/dom/mime_type_array.h"
#include "cobalt/dom/plugin_array.h"
+#include "cobalt/media/web_media_player_factory.h"
#include "cobalt/media_capture/media_devices.h"
#include "cobalt/media_session/media_session.h"
#include "cobalt/script/promise.h"
@@ -42,7 +43,6 @@
Navigator(
script::EnvironmentSettings* settings, const std::string& user_agent,
const std::string& language,
- scoped_refptr<cobalt::media_session::MediaSession> media_session,
scoped_refptr<cobalt::dom::captions::SystemCaptionSettings> captions,
script::ScriptValueFactory* script_value_factory);
@@ -67,8 +67,17 @@
const scoped_refptr<MimeTypeArray>& mime_types() const;
const scoped_refptr<PluginArray>& plugins() const;
- const scoped_refptr<cobalt::media_session::MediaSession>& media_session()
- const;
+ const scoped_refptr<media_session::MediaSession>& media_session();
+
+ // Set maybe freeze callback.
+ void set_maybefreeze_callback(const base::Closure& maybe_freeze_callback) {
+ maybe_freeze_callback_ = maybe_freeze_callback;
+ }
+
+ void set_media_player_factory(
+ const media::WebMediaPlayerFactory* factory) {
+ media_player_factory_ = factory;
+ }
// Web API: extension defined in Encrypted Media Extensions (16 March 2017).
using InterfacePromise = script::Promise<scoped_refptr<script::Wrappable>>;
@@ -124,6 +133,9 @@
script::ScriptValueFactory* script_value_factory_;
base::Optional<bool> key_system_with_attributes_supported_;
+ base::Closure maybe_freeze_callback_;
+ const media::WebMediaPlayerFactory* media_player_factory_ = nullptr;
+
DISALLOW_COPY_AND_ASSIGN(Navigator);
};
diff --git a/src/cobalt/dom/navigator_licenses_test.cc b/src/cobalt/dom/navigator_licenses_test.cc
index d7f2172..cc55b6b 100644
--- a/src/cobalt/dom/navigator_licenses_test.cc
+++ b/src/cobalt/dom/navigator_licenses_test.cc
@@ -24,7 +24,7 @@
testing::StubEnvironmentSettings environment_settings;
scoped_refptr<cobalt::dom::Navigator> navigator =
new cobalt::dom::Navigator(&environment_settings, std::string(),
- std::string(), nullptr, nullptr, nullptr);
+ std::string(), nullptr, nullptr);
ASSERT_TRUE(navigator != nullptr);
EXPECT_FALSE(navigator->licenses().empty());
diff --git a/src/cobalt/dom/on_screen_keyboard_test.cc b/src/cobalt/dom/on_screen_keyboard_test.cc
index 9493146..701c842 100644
--- a/src/cobalt/dom/on_screen_keyboard_test.cc
+++ b/src/cobalt/dom/on_screen_keyboard_test.cc
@@ -30,7 +30,6 @@
#include "cobalt/dom_parser/parser.h"
#include "cobalt/loader/fetcher_factory.h"
#include "cobalt/loader/loader_factory.h"
-#include "cobalt/media_session/media_session.h"
#include "cobalt/script/global_environment.h"
#include "cobalt/script/javascript_engine.h"
#include "cobalt/script/source_code.h"
@@ -222,7 +221,7 @@
base::Closure() /* ran_animation_frame_callbacks */,
dom::Window::CloseCallback() /* window_close */,
base::Closure() /* window_minimize */,
- on_screen_keyboard_bridge_.get(), NULL, NULL,
+ on_screen_keyboard_bridge_.get(), NULL,
dom::Window::OnStartDispatchEventCallback(),
dom::Window::OnStopDispatchEventCallback(),
dom::ScreenshotManager::ProvideScreenshotFunctionCallback(),
diff --git a/src/cobalt/dom/testing/stub_window.h b/src/cobalt/dom/testing/stub_window.h
index 7377579..2631d15 100644
--- a/src/cobalt/dom/testing/stub_window.h
+++ b/src/cobalt/dom/testing/stub_window.h
@@ -32,7 +32,6 @@
#include "cobalt/dom_parser/parser.h"
#include "cobalt/loader/fetcher_factory.h"
#include "cobalt/loader/loader_factory.h"
-#include "cobalt/media_session/media_session.h"
#include "cobalt/script/global_environment.h"
#include "cobalt/script/javascript_engine.h"
#include "starboard/window.h"
@@ -80,7 +79,7 @@
dom::kCspEnforcementEnable, base::Closure() /* csp_policy_changed */,
base::Closure() /* ran_animation_frame_callbacks */,
dom::Window::CloseCallback() /* window_close */,
- base::Closure() /* window_minimize */, NULL, NULL, NULL,
+ base::Closure() /* window_minimize */, NULL, NULL,
dom::Window::OnStartDispatchEventCallback(),
dom::Window::OnStopDispatchEventCallback(),
dom::ScreenshotManager::ProvideScreenshotFunctionCallback(), NULL);
diff --git a/src/cobalt/dom/window.cc b/src/cobalt/dom/window.cc
index 4f89140..2ee9432 100644
--- a/src/cobalt/dom/window.cc
+++ b/src/cobalt/dom/window.cc
@@ -124,7 +124,6 @@
const base::Closure& window_minimize_callback,
OnScreenKeyboardBridge* on_screen_keyboard_bridge,
const scoped_refptr<input::Camera3D>& camera_3d,
- const scoped_refptr<MediaSession>& media_session,
const OnStartDispatchEventCallback& on_start_dispatch_event_callback,
const OnStopDispatchEventCallback& on_stop_dispatch_event_callback,
const ScreenshotManager::ProvideScreenshotFunctionCallback&
@@ -168,7 +167,7 @@
csp_insecure_allowed_token, dom_max_element_depth)))),
document_loader_(nullptr),
history_(new History()),
- navigator_(new Navigator(settings, user_agent, language, media_session,
+ navigator_(new Navigator(settings, user_agent, language,
captions, script_value_factory)),
ALLOW_THIS_IN_INITIALIZER_LIST(
relay_on_load_event_(new RelayLoadEvent(this))),
@@ -705,6 +704,11 @@
tracer->Trace(on_screen_keyboard_);
}
+const scoped_refptr<media_session::MediaSession>
+ Window::media_session() const {
+ return navigator_->media_session();
+}
+
void Window::CacheSplashScreen(const std::string& content,
const base::Optional<std::string>& topic) {
if (splash_screen_cache_callback_.is_null()) {
diff --git a/src/cobalt/dom/window.h b/src/cobalt/dom/window.h
index de6fce2..c572407 100644
--- a/src/cobalt/dom/window.h
+++ b/src/cobalt/dom/window.h
@@ -167,7 +167,6 @@
const base::Closure& window_minimize_callback,
OnScreenKeyboardBridge* on_screen_keyboard_bridge,
const scoped_refptr<input::Camera3D>& camera_3d,
- const scoped_refptr<cobalt::media_session::MediaSession>& media_session,
const OnStartDispatchEventCallback&
start_tracking_dispatch_event_callback,
const OnStopDispatchEventCallback& stop_tracking_dispatch_event_callback,
@@ -355,9 +354,9 @@
void SetCamera3D(const scoped_refptr<input::Camera3D>& camera_3d);
void set_web_media_player_factory(
- media::WebMediaPlayerFactory* web_media_player_factory) {
- html_element_context_->set_web_media_player_factory(
- web_media_player_factory);
+ media::WebMediaPlayerFactory* web_media_player_factory) {
+ html_element_context_->set_web_media_player_factory(
+ web_media_player_factory);
}
// Sets the current application state, forwarding on to the
@@ -408,6 +407,9 @@
bool enable_map_to_mesh() { return enable_map_to_mesh_; }
+ const scoped_refptr<media_session::MediaSession>
+ media_session() const;
+
DEFINE_WRAPPABLE_TYPE(Window);
private:
diff --git a/src/cobalt/dom/window_test.cc b/src/cobalt/dom/window_test.cc
index 8e44fb0..2b1b96f 100644
--- a/src/cobalt/dom/window_test.cc
+++ b/src/cobalt/dom/window_test.cc
@@ -29,7 +29,6 @@
#include "cobalt/dom/testing/stub_environment_settings.h"
#include "cobalt/dom_parser/parser.h"
#include "cobalt/loader/fetcher_factory.h"
-#include "cobalt/media_session/media_session.h"
#include "cobalt/network_bridge/net_poster.h"
#include "cobalt/script/global_environment.h"
#include "cobalt/script/javascript_engine.h"
@@ -74,7 +73,7 @@
kCspEnforcementEnable, base::Closure() /* csp_policy_changed */,
base::Closure() /* ran_animation_frame_callbacks */,
dom::Window::CloseCallback() /* window_close */,
- base::Closure() /* window_minimize */, NULL, NULL, NULL,
+ base::Closure() /* window_minimize */, NULL, NULL,
dom::Window::OnStartDispatchEventCallback(),
dom::Window::OnStopDispatchEventCallback(),
dom::ScreenshotManager::ProvideScreenshotFunctionCallback(), NULL);
diff --git a/src/cobalt/extension/extension_test.cc b/src/cobalt/extension/extension_test.cc
index 38b7c83..d92acd1 100644
--- a/src/cobalt/extension/extension_test.cc
+++ b/src/cobalt/extension/extension_test.cc
@@ -30,23 +30,22 @@
typedef CobaltExtensionPlatformServiceApi ExtensionApi;
const char* kExtensionName = kCobaltExtensionPlatformServiceName;
- const ExtensionApi* extension_api = static_cast<const ExtensionApi*>(
- SbSystemGetExtension(kExtensionName));
+ const ExtensionApi* extension_api =
+ static_cast<const ExtensionApi*>(SbSystemGetExtension(kExtensionName));
if (!extension_api) {
return;
}
EXPECT_STREQ(extension_api->name, kExtensionName);
- EXPECT_TRUE(extension_api->version == 1 ||
- extension_api->version == 2 ||
- extension_api->version == 3) << "Invalid version";
- EXPECT_TRUE(extension_api->Has != NULL);
- EXPECT_TRUE(extension_api->Open != NULL);
- EXPECT_TRUE(extension_api->Close != NULL);
- EXPECT_TRUE(extension_api->Send != NULL);
+ EXPECT_GE(extension_api->version, 1u);
+ EXPECT_LE(extension_api->version, 3u);
+ EXPECT_NE(extension_api->Has, nullptr);
+ EXPECT_NE(extension_api->Open, nullptr);
+ EXPECT_NE(extension_api->Close, nullptr);
+ EXPECT_NE(extension_api->Send, nullptr);
- const ExtensionApi* second_extension_api = static_cast<const ExtensionApi*>(
- SbSystemGetExtension(kExtensionName));
+ const ExtensionApi* second_extension_api =
+ static_cast<const ExtensionApi*>(SbSystemGetExtension(kExtensionName));
EXPECT_EQ(second_extension_api, extension_api)
<< "Extension struct should be a singleton";
}
@@ -55,35 +54,50 @@
typedef CobaltExtensionGraphicsApi ExtensionApi;
const char* kExtensionName = kCobaltExtensionGraphicsName;
- const ExtensionApi* extension_api = static_cast<const ExtensionApi*>(
- SbSystemGetExtension(kExtensionName));
+ const ExtensionApi* extension_api =
+ static_cast<const ExtensionApi*>(SbSystemGetExtension(kExtensionName));
if (!extension_api) {
return;
}
EXPECT_STREQ(extension_api->name, kExtensionName);
- EXPECT_TRUE(extension_api->version == 1 ||
- extension_api->version == 2 ||
- extension_api->version == 3) << "Invalid version";
- EXPECT_TRUE(extension_api->GetMaximumFrameIntervalInMilliseconds != NULL);
- if (extension_api->version >= 2) {
- EXPECT_TRUE(extension_api->GetMinimumFrameIntervalInMilliseconds != NULL);
- }
- if (extension_api->version >= 3) {
- EXPECT_TRUE(extension_api->IsMapToMeshEnabled != NULL);
- }
+ EXPECT_GE(extension_api->version, 1u);
+ EXPECT_LE(extension_api->version, 4u);
+ EXPECT_NE(extension_api->GetMaximumFrameIntervalInMilliseconds, nullptr);
float maximum_frame_interval =
extension_api->GetMaximumFrameIntervalInMilliseconds();
EXPECT_FALSE(std::isnan(maximum_frame_interval));
if (extension_api->version >= 2) {
+ EXPECT_NE(extension_api->GetMinimumFrameIntervalInMilliseconds, nullptr);
float minimum_frame_interval =
- extension_api->GetMinimumFrameIntervalInMilliseconds();
+ extension_api->GetMinimumFrameIntervalInMilliseconds();
EXPECT_GT(minimum_frame_interval, 0);
}
- const ExtensionApi* second_extension_api = static_cast<const ExtensionApi*>(
- SbSystemGetExtension(kExtensionName));
+
+ if (extension_api->version >= 3) {
+ EXPECT_NE(extension_api->IsMapToMeshEnabled, nullptr);
+ }
+
+ if (extension_api->version >= 4) {
+ EXPECT_NE(extension_api->ShouldClearFrameOnShutdown, nullptr);
+ float clear_color_r, clear_color_g, clear_color_b, clear_color_a;
+ if (extension_api->ShouldClearFrameOnShutdown(
+ &clear_color_r, &clear_color_g, &clear_color_b, &clear_color_a)) {
+ EXPECT_GE(clear_color_r, 0.0f);
+ EXPECT_LE(clear_color_r, 1.0f);
+ EXPECT_GE(clear_color_g, 0.0f);
+ EXPECT_LE(clear_color_g, 1.0f);
+ EXPECT_GE(clear_color_b, 0.0f);
+ EXPECT_LE(clear_color_b, 1.0f);
+ EXPECT_GE(clear_color_a, 0.0f);
+ EXPECT_LE(clear_color_a, 1.0f);
+ }
+ }
+
+ const ExtensionApi* second_extension_api =
+ static_cast<const ExtensionApi*>(SbSystemGetExtension(kExtensionName));
EXPECT_EQ(second_extension_api, extension_api)
<< "Extension struct should be a singleton";
}
@@ -99,18 +113,17 @@
}
EXPECT_STREQ(extension_api->name, kExtensionName);
- EXPECT_TRUE(extension_api->version == 1 ||
- extension_api->version == 2 ||
- extension_api->version == 3) << "Invalid version";
- EXPECT_TRUE(extension_api->GetCurrentInstallationIndex != NULL);
- EXPECT_TRUE(extension_api->MarkInstallationSuccessful != NULL);
- EXPECT_TRUE(extension_api->RequestRollForwardToInstallation != NULL);
- EXPECT_TRUE(extension_api->GetInstallationPath != NULL);
- EXPECT_TRUE(extension_api->SelectNewInstallationIndex != NULL);
- EXPECT_TRUE(extension_api->GetAppKey != NULL);
- EXPECT_TRUE(extension_api->GetMaxNumberInstallations != NULL);
- EXPECT_TRUE(extension_api->ResetInstallation != NULL);
- EXPECT_TRUE(extension_api->Reset != NULL);
+ EXPECT_GE(extension_api->version, 1u);
+ EXPECT_LE(extension_api->version, 3u);
+ EXPECT_NE(extension_api->GetCurrentInstallationIndex, nullptr);
+ EXPECT_NE(extension_api->MarkInstallationSuccessful, nullptr);
+ EXPECT_NE(extension_api->RequestRollForwardToInstallation, nullptr);
+ EXPECT_NE(extension_api->GetInstallationPath, nullptr);
+ EXPECT_NE(extension_api->SelectNewInstallationIndex, nullptr);
+ EXPECT_NE(extension_api->GetAppKey, nullptr);
+ EXPECT_NE(extension_api->GetMaxNumberInstallations, nullptr);
+ EXPECT_NE(extension_api->ResetInstallation, nullptr);
+ EXPECT_NE(extension_api->Reset, nullptr);
const ExtensionApi* second_extension_api =
static_cast<const ExtensionApi*>(SbSystemGetExtension(kExtensionName));
EXPECT_EQ(second_extension_api, extension_api)
@@ -128,29 +141,31 @@
}
EXPECT_STREQ(extension_api->name, kExtensionName);
- EXPECT_TRUE(extension_api->version == 1 || extension_api->version == 2);
- EXPECT_TRUE(extension_api->CobaltUserOnExitStrategy != NULL);
- EXPECT_TRUE(extension_api->CobaltRenderDirtyRegionOnly != NULL);
- EXPECT_TRUE(extension_api->CobaltEglSwapInterval != NULL);
- EXPECT_TRUE(extension_api->CobaltFallbackSplashScreenUrl != NULL);
- EXPECT_TRUE(extension_api->CobaltEnableQuic != NULL);
- EXPECT_TRUE(extension_api->CobaltSkiaCacheSizeInBytes != NULL);
- EXPECT_TRUE(extension_api->CobaltOffscreenTargetCacheSizeInBytes != NULL);
- EXPECT_TRUE(extension_api->CobaltEncodedImageCacheSizeInBytes != NULL);
- EXPECT_TRUE(extension_api->CobaltImageCacheSizeInBytes != NULL);
- EXPECT_TRUE(extension_api->CobaltLocalTypefaceCacheSizeInBytes != NULL);
- EXPECT_TRUE(extension_api->CobaltRemoteTypefaceCacheSizeInBytes != NULL);
- EXPECT_TRUE(extension_api->CobaltMeshCacheSizeInBytes != NULL);
- EXPECT_TRUE(extension_api->CobaltSoftwareSurfaceCacheSizeInBytes != NULL);
- EXPECT_TRUE(extension_api->CobaltImageCacheCapacityMultiplierWhenPlayingVideo != NULL);
- EXPECT_TRUE(extension_api->CobaltSkiaGlyphAtlasWidth != NULL);
- EXPECT_TRUE(extension_api->CobaltSkiaGlyphAtlasHeight != NULL);
- EXPECT_TRUE(extension_api->CobaltJsGarbageCollectionThresholdInBytes != NULL);
- EXPECT_TRUE(extension_api->CobaltReduceCpuMemoryBy != NULL);
- EXPECT_TRUE(extension_api->CobaltReduceGpuMemoryBy != NULL);
- EXPECT_TRUE(extension_api->CobaltGcZeal != NULL);
+ EXPECT_GE(extension_api->version, 1u);
+ EXPECT_LE(extension_api->version, 2u);
+ EXPECT_NE(extension_api->CobaltUserOnExitStrategy, nullptr);
+ EXPECT_NE(extension_api->CobaltRenderDirtyRegionOnly, nullptr);
+ EXPECT_NE(extension_api->CobaltEglSwapInterval, nullptr);
+ EXPECT_NE(extension_api->CobaltFallbackSplashScreenUrl, nullptr);
+ EXPECT_NE(extension_api->CobaltEnableQuic, nullptr);
+ EXPECT_NE(extension_api->CobaltSkiaCacheSizeInBytes, nullptr);
+ EXPECT_NE(extension_api->CobaltOffscreenTargetCacheSizeInBytes, nullptr);
+ EXPECT_NE(extension_api->CobaltEncodedImageCacheSizeInBytes, nullptr);
+ EXPECT_NE(extension_api->CobaltImageCacheSizeInBytes, nullptr);
+ EXPECT_NE(extension_api->CobaltLocalTypefaceCacheSizeInBytes, nullptr);
+ EXPECT_NE(extension_api->CobaltRemoteTypefaceCacheSizeInBytes, nullptr);
+ EXPECT_NE(extension_api->CobaltMeshCacheSizeInBytes, nullptr);
+ EXPECT_NE(extension_api->CobaltSoftwareSurfaceCacheSizeInBytes, nullptr);
+ EXPECT_NE(extension_api->CobaltImageCacheCapacityMultiplierWhenPlayingVideo,
+ nullptr);
+ EXPECT_NE(extension_api->CobaltSkiaGlyphAtlasWidth, nullptr);
+ EXPECT_NE(extension_api->CobaltSkiaGlyphAtlasHeight, nullptr);
+ EXPECT_NE(extension_api->CobaltJsGarbageCollectionThresholdInBytes, nullptr);
+ EXPECT_NE(extension_api->CobaltReduceCpuMemoryBy, nullptr);
+ EXPECT_NE(extension_api->CobaltReduceGpuMemoryBy, nullptr);
+ EXPECT_NE(extension_api->CobaltGcZeal, nullptr);
if (extension_api->version >= 2) {
- EXPECT_TRUE(extension_api->CobaltFallbackSplashScreenTopics != NULL);
+ EXPECT_NE(extension_api->CobaltFallbackSplashScreenTopics, nullptr);
}
const ExtensionApi* second_extension_api =
@@ -170,8 +185,8 @@
}
EXPECT_STREQ(extension_api->name, kExtensionName);
- EXPECT_TRUE(extension_api->version == 1);
- EXPECT_TRUE(extension_api->OnMediaSessionStateChanged != NULL);
+ EXPECT_EQ(extension_api->version, 1u);
+ EXPECT_NE(extension_api->OnMediaSessionStateChanged, nullptr);
const ExtensionApi* second_extension_api =
static_cast<const ExtensionApi*>(SbSystemGetExtension(kExtensionName));
diff --git a/src/cobalt/extension/graphics.h b/src/cobalt/extension/graphics.h
index 9c993c5..a1a3b4e 100644
--- a/src/cobalt/extension/graphics.h
+++ b/src/cobalt/extension/graphics.h
@@ -23,8 +23,7 @@
extern "C" {
#endif
-#define kCobaltExtensionGraphicsName \
- "dev.cobalt.extension.Graphics"
+#define kCobaltExtensionGraphicsName "dev.cobalt.extension.Graphics"
typedef struct CobaltExtensionGraphicsApi {
// Name should be the string kCobaltExtensionGraphicsName.
@@ -62,6 +61,20 @@
// Get whether the renderer should support 360 degree video or not.
bool (*IsMapToMeshEnabled)();
+
+ // The fields below this point were added in version 4 or later.
+
+ // Specify whether the framebuffer should be cleared when the graphics
+ // system is shutdown and color to use for clearing. The graphics system
+ // is shutdown on suspend or exit. The clear color values should be in the
+ // range of [0,1]; color values are only used if this function returns true.
+ //
+ // The default behavior is to clear to opaque black on shutdown unless this
+ // API specifies otherwise.
+ bool (*ShouldClearFrameOnShutdown)(float* clear_color_red,
+ float* clear_color_green,
+ float* clear_color_blue,
+ float* clear_color_alpha);
} CobaltExtensionGraphicsApi;
#ifdef __cplusplus
diff --git a/src/cobalt/layout/topmost_event_target.cc b/src/cobalt/layout/topmost_event_target.cc
index df2cd6a..8801fef 100644
--- a/src/cobalt/layout/topmost_event_target.cc
+++ b/src/cobalt/layout/topmost_event_target.cc
@@ -241,9 +241,11 @@
for (scoped_refptr<dom::Element> element = target_element;
element != nearest_common_ancestor;
element = element->parent_element()) {
- element->DispatchEvent(new dom::PointerEvent(
- base::Tokens::pointerenter(), dom::Event::kNotBubbles,
- dom::Event::kNotCancelable, view, *event_init));
+ if (element) {
+ element->DispatchEvent(new dom::PointerEvent(
+ base::Tokens::pointerenter(), dom::Event::kNotBubbles,
+ dom::Event::kNotCancelable, view, *event_init));
+ }
}
}
@@ -254,9 +256,11 @@
for (scoped_refptr<dom::Element> element = target_element;
element != nearest_common_ancestor;
element = element->parent_element()) {
- element->DispatchEvent(new dom::MouseEvent(
- base::Tokens::mouseenter(), dom::Event::kNotBubbles,
- dom::Event::kNotCancelable, view, *event_init));
+ if (element) {
+ element->DispatchEvent(new dom::MouseEvent(
+ base::Tokens::mouseenter(), dom::Event::kNotBubbles,
+ dom::Event::kNotCancelable, view, *event_init));
+ }
}
}
}
diff --git a/src/cobalt/media/base/sbplayer_pipeline.cc b/src/cobalt/media/base/sbplayer_pipeline.cc
index 68abc49..143b238 100644
--- a/src/cobalt/media/base/sbplayer_pipeline.cc
+++ b/src/cobalt/media/base/sbplayer_pipeline.cc
@@ -280,8 +280,13 @@
VideoFrameProvider* video_frame_provider_;
+ // Read audio from the stream if |timestamp_of_last_written_audio_| is less
+ // than |seek_time_| + |kAudioPrerollLimit|, this effectively allows 10
+ // seconds of audio to be written to the SbPlayer after playback startup or
+ // seek.
+ static const SbTime kAudioPrerollLimit = 10 * kSbTimeSecond;
// Don't read audio from the stream more than |kAudioLimit| ahead of the
- // current media time.
+ // current media time during playing.
static const SbTime kAudioLimit = kSbTimeSecond;
// Only call GetMediaTime() from OnNeedData if it has been
// |kMediaTimeCheckInterval| since the last call to GetMediaTime().
@@ -1121,22 +1126,28 @@
kMediaTimeCheckInterval) {
GetMediaTime();
}
- // The estimated time ahead of playback may be negative if no audio has been
- // written.
- SbTime time_ahead_of_playback =
- timestamp_of_last_written_audio_ - last_media_time_;
- // Delay reading audio more than |kAudioLimit| ahead of playback, taking
- // into account that our estimate of playback time might be behind by
+
+ // Delay reading audio more than |kAudioLimit| ahead of playback after the
+ // player has received enough audio for preroll, taking into account that
+ // our estimate of playback time might be behind by
// |kMediaTimeCheckInterval|.
- if (time_ahead_of_playback > (kAudioLimit + kMediaTimeCheckInterval)) {
- SbTime delay_time = (time_ahead_of_playback - kAudioLimit) /
- std::max(playback_rate_, 1.0f);
- task_runner_->PostDelayedTask(
- FROM_HERE, base::Bind(&SbPlayerPipeline::DelayedNeedData, this),
- base::TimeDelta::FromMicroseconds(delay_time));
- audio_read_delayed_ = true;
- return;
+ if (timestamp_of_last_written_audio_ - seek_time_.ToSbTime() >
+ kAudioPrerollLimit) {
+ // The estimated time ahead of playback may be negative if no audio has
+ // been written.
+ SbTime time_ahead_of_playback =
+ timestamp_of_last_written_audio_ - last_media_time_;
+ if (time_ahead_of_playback > (kAudioLimit + kMediaTimeCheckInterval)) {
+ SbTime delay_time = (time_ahead_of_playback - kAudioLimit) /
+ std::max(playback_rate_, 1.0f);
+ task_runner_->PostDelayedTask(
+ FROM_HERE, base::Bind(&SbPlayerPipeline::DelayedNeedData, this),
+ base::TimeDelta::FromMicroseconds(delay_time));
+ audio_read_delayed_ = true;
+ return;
+ }
}
+
audio_read_delayed_ = false;
#endif // SB_API_VERSION >= 11
audio_read_in_progress_ = true;
diff --git a/src/cobalt/media_session/default_media_session_client.cc b/src/cobalt/media_session/default_media_session_client.cc
index 0b4fbac..b1a7c47 100644
--- a/src/cobalt/media_session/default_media_session_client.cc
+++ b/src/cobalt/media_session/default_media_session_client.cc
@@ -36,4 +36,4 @@
} // namespace media_session
} // namespace cobalt
-#endif // COBALT_MEDIA_SESSION_DEFAULT_MEDIA_SESSION_CLIENT_H_
\ No newline at end of file
+#endif // COBALT_MEDIA_SESSION_DEFAULT_MEDIA_SESSION_CLIENT_H_
diff --git a/src/cobalt/media_session/media_session.cc b/src/cobalt/media_session/media_session.cc
index b9d04a0..acc4070 100644
--- a/src/cobalt/media_session/media_session.cc
+++ b/src/cobalt/media_session/media_session.cc
@@ -19,9 +19,8 @@
namespace cobalt {
namespace media_session {
-MediaSession::MediaSession(MediaSessionClient* client)
- : media_session_client_(client),
- playback_state_(kMediaSessionPlaybackStateNone),
+MediaSession::MediaSession()
+ : playback_state_(kMediaSessionPlaybackStateNone),
task_runner_(base::MessageLoop::current()->task_runner()),
is_change_task_queued_(false),
last_position_updated_time_(0) {}
@@ -34,6 +33,13 @@
action_map_.clear();
}
+MediaSession::MediaSession(MediaSessionClient* client)
+ : media_session_client_(client),
+ playback_state_(kMediaSessionPlaybackStateNone),
+ task_runner_(base::MessageLoop::current()->task_runner()),
+ is_change_task_queued_(false),
+ last_position_updated_time_(0) {}
+
void MediaSession::set_metadata(scoped_refptr<MediaMetadata> value) {
metadata_ = value;
MaybeQueueChangeTask(base::TimeDelta());
@@ -77,6 +83,14 @@
return is_change_task_queued_;
}
+void MediaSession::EnsureMediaSessionClient() {
+ if (media_session_client_ == nullptr) {
+ media_session_client_ = media_session::MediaSessionClient::Create();
+ DCHECK(media_session_client_);
+ media_session_client_->set_media_session(this);
+ }
+}
+
void MediaSession::MaybeQueueChangeTask(base::TimeDelta delay) {
DCHECK(task_runner_->BelongsToCurrentThread());
if (is_change_task_queued_) {
diff --git a/src/cobalt/media_session/media_session.h b/src/cobalt/media_session/media_session.h
index 6c1db11..c83b1df 100644
--- a/src/cobalt/media_session/media_session.h
+++ b/src/cobalt/media_session/media_session.h
@@ -21,6 +21,7 @@
#include "base/location.h"
#include "base/logging.h"
#include "base/message_loop/message_loop.h"
+#include "cobalt/media/web_media_player_factory.h"
#include "cobalt/media_session/media_metadata.h"
#include "cobalt/media_session/media_position_state.h"
#include "cobalt/media_session/media_session_action.h"
@@ -58,9 +59,11 @@
ActionMap;
public:
- explicit MediaSession(MediaSessionClient* client);
+ MediaSession();
~MediaSession() override;
+ explicit MediaSession(MediaSessionClient* client);
+
scoped_refptr<MediaMetadata> metadata() const { return metadata_; }
void set_metadata(scoped_refptr<MediaMetadata> value);
@@ -81,6 +84,12 @@
// unit tests.
bool IsChangeTaskQueuedForTesting() const;
+ MediaSessionClient* media_session_client() {
+ return media_session_client_.get();
+ }
+
+ void EnsureMediaSessionClient();
+
private:
void MaybeQueueChangeTask(base::TimeDelta delay);
void OnChanged();
@@ -91,7 +100,7 @@
}
ActionMap action_map_;
- MediaSessionClient* media_session_client_;
+ std::unique_ptr<MediaSessionClient> media_session_client_;
scoped_refptr<MediaMetadata> metadata_;
MediaSessionPlaybackState playback_state_;
scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
diff --git a/src/cobalt/media_session/media_session_client.cc b/src/cobalt/media_session/media_session_client.cc
index 9243556..dc767a3 100644
--- a/src/cobalt/media_session/media_session_client.cc
+++ b/src/cobalt/media_session/media_session_client.cc
@@ -67,7 +67,7 @@
} // namespace
MediaSessionClient::MediaSessionClient(
- scoped_refptr<MediaSession> media_session)
+ MediaSession* media_session)
: media_session_(media_session),
platform_playback_state_(kMediaSessionPlaybackStateNone) {
#if SB_API_VERSION < 11
@@ -91,8 +91,6 @@
MediaSessionClient::~MediaSessionClient() {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
- // Prevent any outstanding MediaSession::OnChanged tasks from calling this.
- media_session_->media_session_client_ = nullptr;
// Destroy the platform's MediaSessionClient, if it exists.
if (extension_ != NULL &&
diff --git a/src/cobalt/media_session/media_session_client.h b/src/cobalt/media_session/media_session_client.h
index 76883d9..4961a91 100644
--- a/src/cobalt/media_session/media_session_client.h
+++ b/src/cobalt/media_session/media_session_client.h
@@ -35,10 +35,9 @@
friend class MediaSession;
public:
- MediaSessionClient() : MediaSessionClient(new MediaSession(this)) {}
-
+ MediaSessionClient(): MediaSessionClient(nullptr) {}
// Injectable MediaSession for tests.
- explicit MediaSessionClient(scoped_refptr<MediaSession> media_session);
+ explicit MediaSessionClient(MediaSession* media_session);
virtual ~MediaSessionClient();
@@ -46,7 +45,7 @@
static std::unique_ptr<MediaSessionClient> Create();
// Retrieves the singleton MediaSession associated with this client.
- scoped_refptr<MediaSession>& GetMediaSession() { return media_session_; }
+ MediaSession* GetMediaSession() { return media_session_; }
// The web app should set the MediaPositionState of the MediaSession object.
// However, if that is not done, then query the web media player factory to
@@ -115,7 +114,8 @@
// Indicate the media session client is active or not depending on the
// media session playback state.
bool is_active() {
- return platform_playback_state_ != kMediaSessionPlaybackStateNone;
+ return session_state_.actual_playback_state() !=
+ kMediaSessionPlaybackStateNone;
}
// Set maybe freeze callback.
@@ -123,9 +123,13 @@
maybe_freeze_callback_ = maybe_freeze_callback;
}
+ void set_media_session(MediaSession* media_session) {
+ media_session_ = media_session;
+ }
+
private:
THREAD_CHECKER(thread_checker_);
- scoped_refptr<MediaSession> media_session_;
+ MediaSession* media_session_;
MediaSessionState session_state_;
MediaSessionPlaybackState platform_playback_state_;
const media::WebMediaPlayerFactory* media_player_factory_ = nullptr;
diff --git a/src/cobalt/media_session/media_session_test.cc b/src/cobalt/media_session/media_session_test.cc
index 36e6660..fcdd413 100644
--- a/src/cobalt/media_session/media_session_test.cc
+++ b/src/cobalt/media_session/media_session_test.cc
@@ -46,25 +46,20 @@
namespace media_session {
namespace {
+class MockMediaSessionClient;
+
class MockCallbackFunction : public MediaSession::MediaSessionActionHandler {
public:
MOCK_CONST_METHOD1(
Run, ReturnValue(const MediaSessionActionDetails& action_details));
};
-class MockMediaSession : public MediaSession {
- public:
- explicit MockMediaSession(MediaSessionClient* client)
- : MediaSession(client) {}
- MOCK_CONST_METHOD0(GetMonotonicNow, SbTimeMonotonic());
-};
-
class MockMediaSessionClient : public MediaSessionClient {
public:
- MockMediaSessionClient() : MediaSessionClient(new MockMediaSession(this)) {}
- MockMediaSession& mock_session() {
- return static_cast<MockMediaSession&>(*GetMediaSession().get());
+ explicit MockMediaSessionClient(MediaSession* media_session) :
+ MediaSessionClient(media_session) {
}
+
void OnMediaSessionStateChanged(const MediaSessionState& session_state)
override {
session_state_ = session_state;
@@ -87,6 +82,18 @@
size_t session_change_count_ = 0;
};
+class MockMediaSession : public MediaSession {
+ public:
+ explicit MockMediaSession(MockMediaSessionClient* client)
+ : MediaSession(client) {}
+
+ MockMediaSessionClient* mock_session_client() {
+ return static_cast<MockMediaSessionClient*>(media_session_client());
+ }
+
+ MOCK_CONST_METHOD0(GetMonotonicNow, SbTimeMonotonic());
+};
+
MATCHER_P(SeekTime, time, "") {
return arg.action() == kMediaSessionActionSeekto && arg.seek_time() == time;
}
@@ -102,85 +109,95 @@
TEST(MediaSessionTest, MediaSessionTest) {
base::MessageLoop message_loop(base::MessageLoop::TYPE_DEFAULT);
- MockMediaSessionClient client;
- scoped_refptr<MediaSession> session = client.GetMediaSession();
+ scoped_refptr<MockMediaSession> session =
+ scoped_refptr<MockMediaSession>(new MockMediaSession(
+ new MockMediaSessionClient(nullptr)));
+ session->media_session_client()->set_media_session(session);
EXPECT_EQ(kMediaSessionPlaybackStateNone, session->playback_state());
session->set_playback_state(kMediaSessionPlaybackStatePlaying);
- client.WaitForSessionStateChange();
- EXPECT_EQ(kMediaSessionPlaybackStatePlaying,
- client.GetMediaSessionState().actual_playback_state());
+ session->mock_session_client()->WaitForSessionStateChange();
+ EXPECT_EQ(kMediaSessionPlaybackStatePlaying, session->mock_session_client()
+ ->GetMediaSessionState().actual_playback_state());
- EXPECT_EQ(client.GetMediaSessionChangeCount(), 1);
+ EXPECT_EQ(session->mock_session_client()->GetMediaSessionChangeCount(), 1);
}
TEST(MediaSessionTest, ActualPlaybackState) {
base::MessageLoop message_loop(base::MessageLoop::TYPE_DEFAULT);
- MockMediaSessionClient client;
- scoped_refptr<MediaSession> session = client.GetMediaSession();
+ scoped_refptr<MockMediaSession> session =
+ scoped_refptr<MockMediaSession>(new MockMediaSession(
+ new MockMediaSessionClient(nullptr)));
+ session->media_session_client()->set_media_session(session);
// Trigger a session state change without impacting playback state.
session->set_metadata(new MediaMetadata);
- client.WaitForSessionStateChange();
- EXPECT_EQ(client.GetMediaSessionChangeCount(), 1);
+ session->mock_session_client()->WaitForSessionStateChange();
+ EXPECT_EQ(session->mock_session_client()->GetMediaSessionChangeCount(), 1);
- EXPECT_EQ(kMediaSessionPlaybackStateNone,
- client.GetMediaSessionState().actual_playback_state());
+ EXPECT_EQ(kMediaSessionPlaybackStateNone, session->mock_session_client()
+ ->GetMediaSessionState().actual_playback_state());
- client.UpdatePlatformPlaybackState(kMediaSessionPlaybackStatePlaying);
+ session->mock_session_client()->UpdatePlatformPlaybackState(
+ kMediaSessionPlaybackStatePlaying);
- client.WaitForSessionStateChange();
- EXPECT_EQ(kMediaSessionPlaybackStatePlaying,
- client.GetMediaSessionState().actual_playback_state());
+ session->mock_session_client()->WaitForSessionStateChange();
+ EXPECT_EQ(kMediaSessionPlaybackStatePlaying, session->mock_session_client()
+ ->GetMediaSessionState().actual_playback_state());
session->set_playback_state(kMediaSessionPlaybackStatePlaying);
- client.WaitForSessionStateChange();
- EXPECT_EQ(kMediaSessionPlaybackStatePlaying,
- client.GetMediaSessionState().actual_playback_state());
+ session->mock_session_client()->WaitForSessionStateChange();
+ EXPECT_EQ(kMediaSessionPlaybackStatePlaying, session->mock_session_client()
+ ->GetMediaSessionState().actual_playback_state());
session->set_playback_state(kMediaSessionPlaybackStatePaused);
- client.WaitForSessionStateChange();
- EXPECT_EQ(kMediaSessionPlaybackStatePlaying,
- client.GetMediaSessionState().actual_playback_state());
+ session->mock_session_client()->WaitForSessionStateChange();
+ EXPECT_EQ(kMediaSessionPlaybackStatePlaying, session->mock_session_client()
+ ->GetMediaSessionState().actual_playback_state());
- client.UpdatePlatformPlaybackState(kMediaSessionPlaybackStatePaused);
+ session->mock_session_client()->UpdatePlatformPlaybackState(
+ kMediaSessionPlaybackStatePaused);
- client.WaitForSessionStateChange();
- EXPECT_EQ(kMediaSessionPlaybackStatePaused,
- client.GetMediaSessionState().actual_playback_state());
+ session->mock_session_client()->WaitForSessionStateChange();
+ EXPECT_EQ(kMediaSessionPlaybackStatePaused, session->mock_session_client()
+ ->GetMediaSessionState().actual_playback_state());
session->set_playback_state(kMediaSessionPlaybackStateNone);
- client.WaitForSessionStateChange();
- EXPECT_EQ(kMediaSessionPlaybackStateNone,
- client.GetMediaSessionState().actual_playback_state());
+ session->mock_session_client()->WaitForSessionStateChange();
+ EXPECT_EQ(kMediaSessionPlaybackStateNone, session->mock_session_client()
+ ->GetMediaSessionState().actual_playback_state());
- client.UpdatePlatformPlaybackState(kMediaSessionPlaybackStateNone);
+ session->mock_session_client()->UpdatePlatformPlaybackState(
+ kMediaSessionPlaybackStateNone);
- client.WaitForSessionStateChange();
- EXPECT_EQ(kMediaSessionPlaybackStateNone,
- client.GetMediaSessionState().actual_playback_state());
+ session->mock_session_client()->WaitForSessionStateChange();
+ EXPECT_EQ(kMediaSessionPlaybackStateNone, session->mock_session_client()
+ ->GetMediaSessionState().actual_playback_state());
- EXPECT_GE(client.GetMediaSessionChangeCount(), 2);
+ EXPECT_GE(session->mock_session_client()->GetMediaSessionChangeCount(), 2);
}
TEST(MediaSessionTest, NullActionClears) {
base::MessageLoop message_loop(base::MessageLoop::TYPE_DEFAULT);
- MockMediaSessionClient client;
- scoped_refptr<MediaSession> session = client.GetMediaSession();
+ scoped_refptr<MockMediaSession> session =
+ scoped_refptr<MockMediaSession>(new MockMediaSession(
+ new MockMediaSessionClient(nullptr)));
+ session->media_session_client()->set_media_session(session);
// Trigger a session state change without impacting playback state.
session->set_metadata(new MediaMetadata);
- client.WaitForSessionStateChange();
- EXPECT_EQ(client.GetMediaSessionChangeCount(), 1);
+ session->mock_session_client()->WaitForSessionStateChange();
+ EXPECT_EQ(session->mock_session_client()->GetMediaSessionChangeCount(), 1);
- MediaSessionState state = client.GetMediaSessionState();
+ MediaSessionState state =
+ session->mock_session_client()->GetMediaSessionState();
EXPECT_EQ(kMediaSessionPlaybackStateNone, state.actual_playback_state());
EXPECT_EQ(0, state.available_actions().to_ulong());
@@ -193,31 +210,38 @@
FakeScriptValue<MediaSession::MediaSessionActionHandler> null_holder(NULL);
session->SetActionHandler(kMediaSessionActionPlay, holder);
- client.WaitForSessionStateChange();
- EXPECT_EQ(1, client.GetMediaSessionState().available_actions().to_ulong());
- client.InvokeAction(kCobaltExtensionMediaSessionActionPlay);
+ session->mock_session_client()->WaitForSessionStateChange();
+ EXPECT_EQ(1, session->mock_session_client()
+ ->GetMediaSessionState().available_actions().to_ulong());
+ session->mock_session_client()->InvokeAction(
+ kCobaltExtensionMediaSessionActionPlay);
session->SetActionHandler(kMediaSessionActionPlay, null_holder);
- client.WaitForSessionStateChange();
- EXPECT_EQ(0, client.GetMediaSessionState().available_actions().to_ulong());
- client.InvokeAction(kCobaltExtensionMediaSessionActionPlay);
+ session->mock_session_client()->WaitForSessionStateChange();
+ EXPECT_EQ(0, session->mock_session_client()
+ ->GetMediaSessionState().available_actions().to_ulong());
+ session->mock_session_client()->InvokeAction(
+ kCobaltExtensionMediaSessionActionPlay);
- EXPECT_GE(client.GetMediaSessionChangeCount(), 3);
+ EXPECT_GE(session->mock_session_client()->GetMediaSessionChangeCount(), 3);
}
TEST(MediaSessionTest, AvailableActions) {
base::MessageLoop message_loop(base::MessageLoop::TYPE_DEFAULT);
- MockMediaSessionClient client;
MediaSessionState state;
- scoped_refptr<MediaSession> session = client.GetMediaSession();
+
+ scoped_refptr<MockMediaSession> session =
+ scoped_refptr<MockMediaSession>(new MockMediaSession(
+ new MockMediaSessionClient(nullptr)));
+ session->media_session_client()->set_media_session(session);
// Trigger a session state change without impacting playback state.
session->set_metadata(new MediaMetadata);
- client.WaitForSessionStateChange();
- EXPECT_EQ(client.GetMediaSessionChangeCount(), 1);
+ session->mock_session_client()->WaitForSessionStateChange();
+ EXPECT_EQ(session->mock_session_client()->GetMediaSessionChangeCount(), 1);
- state = client.GetMediaSessionState();
+ state = session->mock_session_client()->GetMediaSessionState();
EXPECT_EQ(kMediaSessionPlaybackStateNone, state.actual_playback_state());
EXPECT_EQ(0, state.available_actions().to_ulong());
@@ -227,83 +251,86 @@
session->SetActionHandler(kMediaSessionActionPlay, holder);
- client.WaitForSessionStateChange();
- state = client.GetMediaSessionState();
+ session->mock_session_client()->WaitForSessionStateChange();
+ state = session->mock_session_client()->GetMediaSessionState();
EXPECT_EQ(1 << kMediaSessionActionPlay,
state.available_actions().to_ulong());
session->SetActionHandler(kMediaSessionActionPause, holder);
- client.WaitForSessionStateChange();
- state = client.GetMediaSessionState();
+ session->mock_session_client()->WaitForSessionStateChange();
+ state = session->mock_session_client()->GetMediaSessionState();
EXPECT_EQ(1 << kMediaSessionActionPlay,
state.available_actions().to_ulong());
session->SetActionHandler(kMediaSessionActionSeekto, holder);
- client.WaitForSessionStateChange();
- state = client.GetMediaSessionState();
+ session->mock_session_client()->WaitForSessionStateChange();
+ state = session->mock_session_client()->GetMediaSessionState();
EXPECT_EQ(1 << kMediaSessionActionPlay, state.available_actions().to_ulong());
- client.UpdatePlatformPlaybackState(kMediaSessionPlaybackStatePlaying);
+ session->mock_session_client()->UpdatePlatformPlaybackState(
+ kMediaSessionPlaybackStatePlaying);
- client.WaitForSessionStateChange();
- state = client.GetMediaSessionState();
+ session->mock_session_client()->WaitForSessionStateChange();
+ state = session->mock_session_client()->GetMediaSessionState();
EXPECT_EQ(kMediaSessionPlaybackStatePlaying, state.actual_playback_state());
EXPECT_EQ(1 << kMediaSessionActionPause | 1 << kMediaSessionActionSeekto,
state.available_actions().to_ulong());
session->set_playback_state(kMediaSessionPlaybackStatePlaying);
- client.WaitForSessionStateChange();
- state = client.GetMediaSessionState();
+ session->mock_session_client()->WaitForSessionStateChange();
+ state = session->mock_session_client()->GetMediaSessionState();
EXPECT_EQ(kMediaSessionPlaybackStatePlaying, state.actual_playback_state());
EXPECT_EQ(1 << kMediaSessionActionPause | 1 << kMediaSessionActionSeekto,
state.available_actions().to_ulong());
session->set_playback_state(kMediaSessionPlaybackStatePaused);
- client.WaitForSessionStateChange();
- state = client.GetMediaSessionState();
+ session->mock_session_client()->WaitForSessionStateChange();
+ state = session->mock_session_client()->GetMediaSessionState();
EXPECT_EQ(kMediaSessionPlaybackStatePlaying, state.actual_playback_state());
EXPECT_EQ(1 << kMediaSessionActionPause | 1 << kMediaSessionActionSeekto,
state.available_actions().to_ulong());
session->set_playback_state(kMediaSessionPlaybackStatePlaying);
- client.WaitForSessionStateChange();
- state = client.GetMediaSessionState();
+ session->mock_session_client()->WaitForSessionStateChange();
+ state = session->mock_session_client()->GetMediaSessionState();
EXPECT_EQ(kMediaSessionPlaybackStatePlaying, state.actual_playback_state());
EXPECT_EQ(1 << kMediaSessionActionPause | 1 << kMediaSessionActionSeekto,
state.available_actions().to_ulong());
- client.UpdatePlatformPlaybackState(kMediaSessionPlaybackStatePaused);
+ session->mock_session_client()->UpdatePlatformPlaybackState(
+ kMediaSessionPlaybackStatePaused);
- client.WaitForSessionStateChange();
- state = client.GetMediaSessionState();
+ session->mock_session_client()->WaitForSessionStateChange();
+ state = session->mock_session_client()->GetMediaSessionState();
EXPECT_EQ(kMediaSessionPlaybackStatePlaying, state.actual_playback_state());
EXPECT_EQ(1 << kMediaSessionActionPause | 1 << kMediaSessionActionSeekto,
state.available_actions().to_ulong());
session->set_playback_state(kMediaSessionPlaybackStateNone);
- client.WaitForSessionStateChange();
- state = client.GetMediaSessionState();
+ session->mock_session_client()->WaitForSessionStateChange();
+ state = session->mock_session_client()->GetMediaSessionState();
EXPECT_EQ(kMediaSessionPlaybackStateNone, state.actual_playback_state());
EXPECT_EQ(1 << kMediaSessionActionPlay, state.available_actions().to_ulong());
session->set_playback_state(kMediaSessionPlaybackStatePaused);
- client.WaitForSessionStateChange();
- state = client.GetMediaSessionState();
+ session->mock_session_client()->WaitForSessionStateChange();
+ state = session->mock_session_client()->GetMediaSessionState();
EXPECT_EQ(kMediaSessionPlaybackStatePaused, state.actual_playback_state());
EXPECT_EQ(1 << kMediaSessionActionPlay | 1 << kMediaSessionActionSeekto,
state.available_actions().to_ulong());
- client.UpdatePlatformPlaybackState(kMediaSessionPlaybackStateNone);
+ session->mock_session_client()->UpdatePlatformPlaybackState(
+ kMediaSessionPlaybackStateNone);
- client.WaitForSessionStateChange();
- state = client.GetMediaSessionState();
+ session->mock_session_client()->WaitForSessionStateChange();
+ state = session->mock_session_client()->GetMediaSessionState();
EXPECT_EQ(kMediaSessionPlaybackStatePaused, state.actual_playback_state());
EXPECT_EQ(1 << kMediaSessionActionPlay | 1 << kMediaSessionActionSeekto,
state.available_actions().to_ulong());
@@ -312,8 +339,10 @@
TEST(MediaSessionTest, InvokeAction) {
base::MessageLoop message_loop(base::MessageLoop::TYPE_DEFAULT);
- MockMediaSessionClient client;
- scoped_refptr<MediaSession> session = client.GetMediaSession();
+ scoped_refptr<MockMediaSession> session =
+ scoped_refptr<MockMediaSession>(new MockMediaSession(
+ new MockMediaSessionClient(nullptr)));
+ session->media_session_client()->set_media_session(session);
MockCallbackFunction cf;
FakeScriptValue<MediaSession::MediaSessionActionHandler> holder(&cf);
@@ -325,14 +354,16 @@
details->set_action(kMediaSessionActionSeekto);
details->set_seek_time(1.2);
- client.InvokeAction(std::move(details));
+ session->mock_session_client()->InvokeAction(std::move(details));
}
TEST(MediaSessionTest, SeekDetails) {
base::MessageLoop message_loop(base::MessageLoop::TYPE_DEFAULT);
- MockMediaSessionClient client;
- scoped_refptr<MediaSession> session = client.GetMediaSession();
+ scoped_refptr<MockMediaSession> session =
+ scoped_refptr<MockMediaSession>(new MockMediaSession(
+ new MockMediaSessionClient(nullptr)));
+ session->media_session_client()->set_media_session(session);
MockCallbackFunction cf;
FakeScriptValue<MediaSession::MediaSessionActionHandler> holder(&cf);
@@ -344,41 +375,46 @@
EXPECT_CALL(cf, Run(SeekNoOffset(kMediaSessionActionSeekforward)))
.WillOnce(Return(CallbackResult<void>()));
- client.InvokeAction(kCobaltExtensionMediaSessionActionSeekforward);
+ session->mock_session_client()->InvokeAction(
+ kCobaltExtensionMediaSessionActionSeekforward);
EXPECT_CALL(cf, Run(SeekNoOffset(kMediaSessionActionSeekbackward)))
.WillOnce(Return(CallbackResult<void>()));
- client.InvokeAction(kCobaltExtensionMediaSessionActionSeekbackward);
+ session->mock_session_client()->InvokeAction(
+ kCobaltExtensionMediaSessionActionSeekbackward);
EXPECT_CALL(cf, Run(SeekTime(1.2))).WillOnce(Return(CallbackResult<void>()));
CobaltExtensionMediaSessionActionDetailsInit(
&details, kCobaltExtensionMediaSessionActionSeekto);
details.seek_time = 1.2;
- client.InvokeCobaltExtensionAction(details);
+ session->mock_session_client()->InvokeCobaltExtensionAction(details);
EXPECT_CALL(cf, Run(SeekOffset(kMediaSessionActionSeekforward, 3.4)))
.WillOnce(Return(CallbackResult<void>()));
CobaltExtensionMediaSessionActionDetailsInit(
&details, kCobaltExtensionMediaSessionActionSeekforward);
details.seek_offset = 3.4;
- client.InvokeCobaltExtensionAction(details);
+ session->mock_session_client()->InvokeCobaltExtensionAction(details);
EXPECT_CALL(cf, Run(SeekOffset(kMediaSessionActionSeekbackward, 5.6)))
.WillOnce(Return(CallbackResult<void>()));
CobaltExtensionMediaSessionActionDetailsInit(
&details, kCobaltExtensionMediaSessionActionSeekbackward);
details.seek_offset = 5.6;
- client.InvokeCobaltExtensionAction(details);
+ session->mock_session_client()->InvokeCobaltExtensionAction(details);
- client.WaitForSessionStateChange();
- EXPECT_GE(client.GetMediaSessionChangeCount(), 0);
+ session->mock_session_client()->WaitForSessionStateChange();
+ EXPECT_GE(session->mock_session_client()->GetMediaSessionChangeCount(), 0);
}
TEST(MediaSessionTest, PositionState) {
base::MessageLoop message_loop(base::MessageLoop::TYPE_DEFAULT);
- MockMediaSessionClient client;
- MockMediaSession& session = client.mock_session();
+ scoped_refptr<MockMediaSession> session =
+ scoped_refptr<MockMediaSession>(new MockMediaSession(
+ new MockMediaSessionClient(nullptr)));
+ session->media_session_client()->set_media_session(session);
+
MediaSessionState state;
SbTimeMonotonic start_time = 1111111111;
@@ -389,23 +425,23 @@
position_state->set_position(10.0);
// Trigger a session state change without impacting playback state.
- session.set_metadata(new MediaMetadata);
- client.WaitForSessionStateChange();
- EXPECT_EQ(client.GetMediaSessionChangeCount(), 1);
+ session->set_metadata(new MediaMetadata);
+ session->mock_session_client()->WaitForSessionStateChange();
+ EXPECT_EQ(session->mock_session_client()->GetMediaSessionChangeCount(), 1);
// Position state not yet reported
- state = client.GetMediaSessionState();
+ state = session->mock_session_client()->GetMediaSessionState();
EXPECT_EQ(0,
state.GetCurrentPlaybackPosition(start_time + 999 * kSbTimeSecond));
EXPECT_EQ(0, state.duration());
EXPECT_EQ(0.0, state.actual_playback_rate());
// Forward playback
- EXPECT_CALL(session, GetMonotonicNow()).WillOnce(Return(start_time));
+ EXPECT_CALL(*session, GetMonotonicNow()).WillOnce(Return(start_time));
position_state->set_playback_rate(1.0);
- session.SetPositionState(position_state);
- client.WaitForSessionStateChange();
- state = client.GetMediaSessionState();
+ session->SetPositionState(position_state);
+ session->mock_session_client()->WaitForSessionStateChange();
+ state = session->mock_session_client()->GetMediaSessionState();
EXPECT_EQ((10 + 50) * kSbTimeSecond,
state.GetCurrentPlaybackPosition(start_time + 50 * kSbTimeSecond));
EXPECT_EQ(100 * kSbTimeSecond,
@@ -414,11 +450,11 @@
EXPECT_EQ(1.0, state.actual_playback_rate());
// Fast playback
- EXPECT_CALL(session, GetMonotonicNow()).WillOnce(Return(start_time));
+ EXPECT_CALL(*session, GetMonotonicNow()).WillOnce(Return(start_time));
position_state->set_playback_rate(2.0);
- session.SetPositionState(position_state);
- client.WaitForSessionStateChange();
- state = client.GetMediaSessionState();
+ session->SetPositionState(position_state);
+ session->mock_session_client()->WaitForSessionStateChange();
+ state = session->mock_session_client()->GetMediaSessionState();
EXPECT_EQ((10 + 2 * 20) * kSbTimeSecond,
state.GetCurrentPlaybackPosition(start_time + 20 * kSbTimeSecond));
EXPECT_EQ(100 * kSbTimeSecond,
@@ -427,11 +463,11 @@
EXPECT_EQ(2.0, state.actual_playback_rate());
// Reverse playback
- EXPECT_CALL(session, GetMonotonicNow()).WillOnce(Return(start_time));
+ EXPECT_CALL(*session, GetMonotonicNow()).WillOnce(Return(start_time));
position_state->set_playback_rate(-1.0);
- session.SetPositionState(position_state);
- client.WaitForSessionStateChange();
- state = client.GetMediaSessionState();
+ session->SetPositionState(position_state);
+ session->mock_session_client()->WaitForSessionStateChange();
+ state = session->mock_session_client()->GetMediaSessionState();
EXPECT_EQ(0 * kSbTimeSecond,
state.GetCurrentPlaybackPosition(start_time + 20 * kSbTimeSecond));
EXPECT_EQ((10 - 3) * kSbTimeSecond,
@@ -440,12 +476,12 @@
EXPECT_EQ(-1.0, state.actual_playback_rate());
// Indefinite duration (live) playback
- EXPECT_CALL(session, GetMonotonicNow()).WillOnce(Return(start_time));
+ EXPECT_CALL(*session, GetMonotonicNow()).WillOnce(Return(start_time));
position_state->set_duration(std::numeric_limits<double>::infinity());
position_state->set_playback_rate(1.0);
- session.SetPositionState(position_state);
- client.WaitForSessionStateChange();
- state = client.GetMediaSessionState();
+ session->SetPositionState(position_state);
+ session->mock_session_client()->WaitForSessionStateChange();
+ state = session->mock_session_client()->GetMediaSessionState();
EXPECT_EQ(10 * kSbTimeSecond + 1 * kSbTimeDay,
state.GetCurrentPlaybackPosition(start_time + 1 * kSbTimeDay));
EXPECT_EQ(kSbTimeMax, state.duration());
@@ -454,45 +490,47 @@
// Paused playback
// (Actual playback rate is 0.0, so position is the last reported position.
// The web app should update position and playback states together.)
- session.set_playback_state(kMediaSessionPlaybackStatePaused);
- client.WaitForSessionStateChange();
- state = client.GetMediaSessionState();
+ session->set_playback_state(kMediaSessionPlaybackStatePaused);
+ session->mock_session_client()->WaitForSessionStateChange();
+ state = session->mock_session_client()->GetMediaSessionState();
EXPECT_EQ(10 * kSbTimeSecond,
state.GetCurrentPlaybackPosition(start_time + 999 * kSbTimeSecond));
EXPECT_EQ(kSbTimeMax, state.duration());
EXPECT_EQ(0.0, state.actual_playback_rate());
- session.set_playback_state(kMediaSessionPlaybackStatePlaying);
+ session->set_playback_state(kMediaSessionPlaybackStatePlaying);
// Position state cleared
- EXPECT_CALL(session, GetMonotonicNow()).WillOnce(Return(start_time));
- session.SetPositionState(base::nullopt);
- client.WaitForSessionStateChange();
- state = client.GetMediaSessionState();
+ EXPECT_CALL(*session, GetMonotonicNow()).WillOnce(Return(start_time));
+ session->SetPositionState(base::nullopt);
+ session->mock_session_client()->WaitForSessionStateChange();
+ state = session->mock_session_client()->GetMediaSessionState();
EXPECT_EQ(0,
state.GetCurrentPlaybackPosition(start_time + 999 * kSbTimeSecond));
EXPECT_EQ(0, state.duration());
EXPECT_EQ(0.0, state.actual_playback_rate());
- EXPECT_GE(client.GetMediaSessionChangeCount(), 3);
+ EXPECT_GE(session->mock_session_client()->GetMediaSessionChangeCount(), 3);
}
TEST(MediaSessionTest, Metadata) {
base::MessageLoop message_loop(base::MessageLoop::TYPE_DEFAULT);
- MockMediaSessionClient client;
- MockMediaSession& session = client.mock_session();
+ scoped_refptr<MockMediaSession> session =
+ scoped_refptr<MockMediaSession>(new MockMediaSession(
+ new MockMediaSessionClient(nullptr)));
+ session->media_session_client()->set_media_session(session);
MediaSessionState state;
MediaMetadataInit init_metadata;
base::Optional<MediaMetadataInit> state_metadata;
// Trigger a session state change without impacting metadata.
- session.set_playback_state(kMediaSessionPlaybackStateNone);
- client.WaitForSessionStateChange();
- EXPECT_EQ(client.GetMediaSessionChangeCount(), 1);
+ session->set_playback_state(kMediaSessionPlaybackStateNone);
+ session->mock_session_client()->WaitForSessionStateChange();
+ EXPECT_EQ(session->mock_session_client()->GetMediaSessionChangeCount(), 1);
// Metadata not yet set
- state = client.GetMediaSessionState();
+ state = session->mock_session_client()->GetMediaSessionState();
state_metadata = state.metadata();
EXPECT_FALSE(state.has_metadata());
EXPECT_FALSE(state_metadata.has_value());
@@ -507,11 +545,11 @@
script::Sequence<MediaImage> artwork;
artwork.push_back(art_image);
init_metadata.set_artwork(artwork);
- session.set_metadata(
+ session->set_metadata(
scoped_refptr<MediaMetadata>(new MediaMetadata(init_metadata)));
- client.WaitForSessionStateChange();
- state = client.GetMediaSessionState();
+ session->mock_session_client()->WaitForSessionStateChange();
+ state = session->mock_session_client()->GetMediaSessionState();
state_metadata = state.metadata();
EXPECT_TRUE(state.has_metadata());
EXPECT_TRUE(state_metadata.has_value());
@@ -521,7 +559,7 @@
EXPECT_EQ(1, state_metadata->artwork().size());
EXPECT_EQ("http://art.image", state_metadata->artwork().at(0).src());
- EXPECT_GE(client.GetMediaSessionChangeCount(), 2);
+ EXPECT_GE(session->mock_session_client()->GetMediaSessionChangeCount(), 2);
}
} // namespace
diff --git a/src/cobalt/media_stream/media_stream_test.gyp b/src/cobalt/media_stream/media_stream_test.gyp
index a7cc5b1..aac127c 100644
--- a/src/cobalt/media_stream/media_stream_test.gyp
+++ b/src/cobalt/media_stream/media_stream_test.gyp
@@ -30,6 +30,7 @@
'testing/mock_media_stream_audio_track.h',
],
'dependencies': [
+ '<@(cobalt_platform_dependencies)',
'<(DEPTH)/cobalt/dom/dom.gyp:dom',
'<(DEPTH)/cobalt/media_stream/media_stream.gyp:media_stream',
'<(DEPTH)/testing/gmock.gyp:gmock',
diff --git a/src/cobalt/renderer/pipeline.cc b/src/cobalt/renderer/pipeline.cc
index 97bef85..a78f0ed 100644
--- a/src/cobalt/renderer/pipeline.cc
+++ b/src/cobalt/renderer/pipeline.cc
@@ -24,12 +24,14 @@
#include "cobalt/base/address_sanitizer.h"
#include "cobalt/base/cobalt_paths.h"
#include "cobalt/base/polymorphic_downcast.h"
+#include "cobalt/extension/graphics.h"
#include "cobalt/math/rect_f.h"
#include "cobalt/render_tree/brush.h"
#include "cobalt/render_tree/composition_node.h"
#include "cobalt/render_tree/dump_render_tree_to_string.h"
#include "cobalt/render_tree/rect_node.h"
#include "nb/memory_scope.h"
+#include "starboard/system.h"
using cobalt::render_tree::Node;
using cobalt::render_tree::animations::AnimateNode;
@@ -38,6 +40,7 @@
namespace renderer {
namespace {
+
#if !defined(COBALT_MINIMUM_FRAME_TIME_IN_MILLISECONDS)
// This default value has been moved from cobalt/build/cobalt_configuration.gypi
// in favor of the usage of
@@ -76,6 +79,34 @@
}
}
+bool ShouldClearFrameOnShutdown(render_tree::ColorRGBA* out_clear_color) {
+#if SB_API_VERSION >= 11
+ const CobaltExtensionGraphicsApi* graphics_extension =
+ static_cast<const CobaltExtensionGraphicsApi*>(
+ SbSystemGetExtension(kCobaltExtensionGraphicsName));
+ if (graphics_extension &&
+ strcmp(graphics_extension->name, kCobaltExtensionGraphicsName) == 0 &&
+ graphics_extension->version >= 4) {
+ float r, g, b, a;
+ if (graphics_extension->ShouldClearFrameOnShutdown(&r, &g, &b, &a)) {
+ out_clear_color->set_r(r);
+ out_clear_color->set_g(g);
+ out_clear_color->set_b(b);
+ out_clear_color->set_a(a);
+ return true;
+ }
+ return false;
+ }
+#endif
+
+ // Default is to clear to opaque black.
+ out_clear_color->set_r(0.0f);
+ out_clear_color->set_g(0.0f);
+ out_clear_color->set_b(0.0f);
+ out_clear_color->set_a(1.0f);
+ return true;
+}
+
} // namespace
Pipeline::Pipeline(const CreateRasterizerFunction& create_rasterizer_function,
@@ -329,13 +360,13 @@
minimum_frame_interval_milliseconds =
COBALT_MINIMUM_FRAME_TIME_IN_MILLISECONDS;
} else {
- DLOG(ERROR) <<
- "COBALT_MINIMUM_FRAME_TIME_IN_MILLISECONDS and "
- "CobaltExtensionGraphicsApi::GetMinimumFrameIntervalInMilliseconds"
- "are both defined."
- "Remove the 'cobalt_minimum_frame_time_in_milliseconds' ";
- "from ../gyp_configuration.gypi in favor of the usage of "
- "CobaltExtensionGraphicsApi::GetMinimumFrameIntervalInMilliseconds."
+ DLOG(ERROR)
+ << "COBALT_MINIMUM_FRAME_TIME_IN_MILLISECONDS and "
+ "CobaltExtensionGraphicsApi::GetMinimumFrameIntervalInMilliseconds"
+ "are both defined."
+ "Remove the 'cobalt_minimum_frame_time_in_milliseconds' ";
+ "from ../gyp_configuration.gypi in favor of the usage of "
+ "CobaltExtensionGraphicsApi::GetMinimumFrameIntervalInMilliseconds."
}
#else
if (minimum_frame_interval_milliseconds < 0.0f) {
@@ -373,11 +404,13 @@
bool is_new_render_tree = submission.render_tree != last_render_tree_;
bool has_render_tree_changed =
!last_animations_expired_ || is_new_render_tree;
- bool force_rasterize = submit_even_if_render_tree_is_unchanged_ ||
- fps_overlay_update_pending_;
+ bool force_rasterize =
+ submit_even_if_render_tree_is_unchanged_ || fps_overlay_update_pending_;
- float maximum_frame_interval_milliseconds = graphics_context_ ?
- graphics_context_->GetMaximumFrameIntervalInMilliseconds() : -1.0f;
+ float maximum_frame_interval_milliseconds =
+ graphics_context_
+ ? graphics_context_->GetMaximumFrameIntervalInMilliseconds()
+ : -1.0f;
if (maximum_frame_interval_milliseconds >= 0.0f) {
base::TimeDelta max_time_between_rasterize =
base::TimeDelta::FromMillisecondsD(maximum_frame_interval_milliseconds);
@@ -617,18 +650,18 @@
// Shutdown the FPS overlay which may reference render trees.
fps_overlay_ = base::nullopt;
- // Submit a black fullscreen rect node to clear the display before shutting
+ // Submit a fullscreen rect node to clear the display before shutting
// down. This can be helpful if we quit while playing a video via
// punch-through, which may result in unexpected images/colors appearing for
// a flicker behind the display.
- if (render_target_ && (clear_on_shutdown_mode_ == kClearToBlack)) {
- rasterizer_->Submit(
- new render_tree::RectNode(
- math::RectF(render_target_->GetSize()),
- std::unique_ptr<render_tree::Brush>(
- new render_tree::SolidColorBrush(
- render_tree::ColorRGBA(0.0f, 0.0f, 0.0f, 1.0f)))),
- render_target_);
+ render_tree::ColorRGBA clear_color;
+ if (render_target_ && clear_on_shutdown_mode_ == kClearAccordingToPlatform &&
+ ShouldClearFrameOnShutdown(&clear_color)) {
+ rasterizer_->Submit(new render_tree::RectNode(
+ math::RectF(render_target_->GetSize()),
+ std::unique_ptr<render_tree::Brush>(
+ new render_tree::SolidColorBrush(clear_color))),
+ render_target_);
}
// This potential reference to a render tree whose animations may have ended
diff --git a/src/cobalt/renderer/pipeline.h b/src/cobalt/renderer/pipeline.h
index bbb9658..5848d95 100644
--- a/src/cobalt/renderer/pipeline.h
+++ b/src/cobalt/renderer/pipeline.h
@@ -58,7 +58,12 @@
RasterizationCompleteCallback;
enum ShutdownClearMode {
- kClearToBlack,
+ // Query CobaltExtensionGraphicsApi's ShouldClearFrameOnShutdown for
+ // shutdown behavior.
+ kClearAccordingToPlatform,
+
+ // Do not clear regardless of what CobaltExtensionGraphicsApi's
+ // ShouldClearFrameOnShutdown specifies.
kNoClear,
};
diff --git a/src/cobalt/renderer/rasterizer/egl/hardware_rasterizer.cc b/src/cobalt/renderer/rasterizer/egl/hardware_rasterizer.cc
index 801112c..1f04c7a 100644
--- a/src/cobalt/renderer/rasterizer/egl/hardware_rasterizer.cc
+++ b/src/cobalt/renderer/rasterizer/egl/hardware_rasterizer.cc
@@ -234,7 +234,7 @@
uint32_t untouched_states =
kMSAAEnable_GrGLBackendState | kStencil_GrGLBackendState |
kPixelStore_GrGLBackendState | kFixedFunction_GrGLBackendState |
- kPathRendering_GrGLBackendState | kMisc_GrGLBackendState;
+ kPathRendering_GrGLBackendState;
GetFallbackContext()->resetContext(~untouched_states & kAll_GrBackendState);
}
diff --git a/src/cobalt/renderer/renderer_module.cc b/src/cobalt/renderer/renderer_module.cc
index 6b52456..9783414 100644
--- a/src/cobalt/renderer/renderer_module.cc
+++ b/src/cobalt/renderer/renderer_module.cc
@@ -102,7 +102,7 @@
// deprecate the submit_even_if_render_tree_is_unchanged.
false,
#endif
- renderer::Pipeline::kClearToBlack, pipeline_options));
+ renderer::Pipeline::kClearAccordingToPlatform, pipeline_options));
}
}
diff --git a/src/cobalt/site/docs/reference/starboard/modules/configuration.md b/src/cobalt/site/docs/reference/starboard/modules/configuration.md
index fff4d9a..5e41790 100644
--- a/src/cobalt/site/docs/reference/starboard/modules/configuration.md
+++ b/src/cobalt/site/docs/reference/starboard/modules/configuration.md
@@ -53,11 +53,6 @@
SB_DEPRECATED_EXTERNAL(...) annotates the function as deprecated for external
clients, but not deprecated for starboard.
-### SB_DISALLOW_COPY_AND_ASSIGN(TypeName) ###
-
-A macro to disallow the copy constructor and operator= functions This should be
-used in the private: declarations for a class
-
### SB_EXPERIMENTAL_API_VERSION ###
The API version that is currently open for changes, and therefore is not stable
diff --git a/src/cobalt/speech/sandbox/sandbox.gyp b/src/cobalt/speech/sandbox/sandbox.gyp
index 03be453..25aaed0 100644
--- a/src/cobalt/speech/sandbox/sandbox.gyp
+++ b/src/cobalt/speech/sandbox/sandbox.gyp
@@ -28,6 +28,7 @@
'speech_sandbox_main.cc',
],
'dependencies': [
+ '<@(cobalt_platform_dependencies)',
'<(DEPTH)/cobalt/audio/audio.gyp:audio',
'<(DEPTH)/cobalt/base/base.gyp:base',
'<(DEPTH)/cobalt/debug/debug.gyp:console_command_manager',
diff --git a/src/cobalt/tools/automated_testing/cobalt_runner.py b/src/cobalt/tools/automated_testing/cobalt_runner.py
index 1efd7dd..003edf5 100644
--- a/src/cobalt/tools/automated_testing/cobalt_runner.py
+++ b/src/cobalt/tools/automated_testing/cobalt_runner.py
@@ -9,10 +9,10 @@
import os
import re
import sys
-import thread
import threading
import time
import traceback
+import thread
import _env # pylint: disable=unused-import
from cobalt.tools.automated_testing import c_val_names
@@ -26,7 +26,8 @@
RE_WEBDRIVER_FAILED = re.compile(r'Could not start WebDriver server')
# Pattern to match Cobalt log line for when a WindowDriver has been created.
RE_WINDOWDRIVER_CREATED = re.compile(
- r'^\[[\d:]+/[\d.]+:INFO:browser_module\.cc\(\d+\)\] Created WindowDriver: ID=\S+'
+ (r'^\[[\d:]+/[\d.]+:INFO:browser_module\.cc\(\d+\)\] Created WindowDriver: '
+ r'ID=\S+')
)
# Pattern to match Cobalt log line for when a WebModule is has been loaded.
RE_WEBMODULE_LOADED = re.compile(
@@ -247,7 +248,7 @@
self.WaitForStart()
except KeyboardInterrupt:
# potentially from thread.interrupt_main(). We will treat as
- # a timeout regardless
+ # a timeout regardless.
self.Exit(should_fail=True)
raise TimeoutException
@@ -286,8 +287,8 @@
self.runner_thread.join(COBALT_EXIT_TIMEOUT_SECONDS)
if self.runner_thread.isAlive():
sys.stderr.write(
- '***Runner thread still alive after sending graceful shutdown command, try again by killing app***\n'
- )
+ '***Runner thread still alive after sending graceful shutdown '
+ 'command, try again by killing app***\n')
self.launcher.Kill()
# Once the write end of the pipe has been closed by the launcher, the reader
# thread will get EOF and exit.
@@ -328,7 +329,7 @@
logging.info('Cobalt terminated.')
if not self.failed and self.success_message:
print('{}\n'.format(self.success_message))
- logging.info('{}\n'.format(self.success_message))
+ logging.info('%s\n', self.success_message)
# pylint: disable=broad-except
except Exception as ex:
sys.stderr.write('Exception running Cobalt ' + str(ex))
@@ -370,15 +371,14 @@
"""
javascript_code = 'return h5vcc.cVal.getValue(\'{}\')'.format(cval_name)
cval_string = self.ExecuteJavaScript(javascript_code)
- if cval_string is None:
- return None
- else:
+ if cval_string:
try:
# Try to parse numbers and booleans.
return json.loads(cval_string)
except ValueError:
# If we can't parse a value, return the cval string as-is.
return cval_string
+ return None
def GetCvalBatch(self, cval_name_list):
"""Retrieves a batch of cvals.
@@ -465,6 +465,8 @@
Returns:
Array of selected elements
"""
+ elements = None
+
# The retry part below is a temporary workaround to handle command
# failures during a short window of stale Cobalt WindowDriver
# after navigation. We only introduced it because of limited time budget
diff --git a/src/cobalt/updater/configurator.cc b/src/cobalt/updater/configurator.cc
index aacee6a..f48c66a 100644
--- a/src/cobalt/updater/configurator.cc
+++ b/src/cobalt/updater/configurator.cc
@@ -28,50 +28,35 @@
// Default time constants.
const int kDelayOneMinute = 60;
const int kDelayOneHour = kDelayOneMinute * 60;
-
-#if defined(COBALT_BUILD_TYPE_DEBUG) || defined(COBALT_BUILD_TYPE_DEVEL)
-const std::set<std::string> valid_channels = {"dev"};
-const std::string kDefaultUpdaterChannel = "dev";
-#elif defined(COBALT_BUILD_TYPE_QA)
const std::set<std::string> valid_channels = {
- // Default channel for qa builds
- "qa",
- // Test an update with higher version than qa channel
- "test",
- // Test an update with mismatched sabi
- "tmsabi",
- // Test an update that does nothing
- "tnoop",
- // Test an update that crashes
- "tcrash",
- // Test an update that fails verification
- "tfailv",
- // Test a series of continuous updates with two channels
- "tseries1", "tseries2",
-};
-const std::string kDefaultUpdaterChannel = "qa";
-#elif defined(COBALT_BUILD_TYPE_GOLD)
-const std::set<std::string> valid_channels = {
- // Default channel for gold builds
- "prod",
- // Channel for dogfooders
+ // Default channel for debug/devel builds.
+ "dev",
+ // Channel for dogfooders.
"dogfood",
+ // Default channel for gold builds.
+ "prod",
// Default channel for qa builds. A gold build can switch to this channel to
// get an official qa build.
"qa",
- // Test an update with higher version than prod channel
+ // Test an update with higher version than prod channel.
"test",
- // Test an update with mismatched sabi
+ // Test an update with mismatched sabi.
"tmsabi",
- // Test an update that does nothing
+ // Test an update that does nothing.
"tnoop",
- // Test an update that crashes
+ // Test an update that crashes.
"tcrash",
- // Test an update that fails verification
+ // Test an update that fails verification.
"tfailv",
- // Test a series of continuous updates with two channels
+ // Test a series of continuous updates with two channels.
"tseries1", "tseries2",
};
+
+#if defined(COBALT_BUILD_TYPE_DEBUG) || defined(COBALT_BUILD_TYPE_DEVEL)
+const std::string kDefaultUpdaterChannel = "dev";
+#elif defined(COBALT_BUILD_TYPE_QA)
+const std::string kDefaultUpdaterChannel = "qa";
+#elif defined(COBALT_BUILD_TYPE_GOLD)
const std::string kDefaultUpdaterChannel = "prod";
#endif
diff --git a/src/cobalt/updater/noop_sandbox.cc b/src/cobalt/updater/noop_sandbox.cc
index d9ce028..5f63965 100644
--- a/src/cobalt/updater/noop_sandbox.cc
+++ b/src/cobalt/updater/noop_sandbox.cc
@@ -15,7 +15,12 @@
// This is a test app for Evergreen that does nothing.
#include "starboard/event.h"
+#include "starboard/system.h"
+#include "starboard/thread.h"
+#include "starboard/time.h"
void SbEventHandle(const SbEvent* event) {
- // noop
+ // No-op app. Exit after 1s.
+ SbThreadSleep(kSbTimeSecond);
+ SbSystemRequestStop(0);
}
diff --git a/src/cobalt/websocket/websocket.gyp b/src/cobalt/websocket/websocket.gyp
index c3bfb3a..4ba8d9a 100644
--- a/src/cobalt/websocket/websocket.gyp
+++ b/src/cobalt/websocket/websocket.gyp
@@ -33,6 +33,7 @@
'web_socket_impl.h',
],
'dependencies': [
+ '<@(cobalt_platform_dependencies)',
'<(DEPTH)/cobalt/base/base.gyp:base',
'<(DEPTH)/cobalt/browser/browser_bindings_gen.gyp:generated_types',
'<(DEPTH)/cobalt/dom/dom.gyp:dom',
diff --git a/src/cobalt/xhr/url_fetcher_buffer_writer.cc b/src/cobalt/xhr/url_fetcher_buffer_writer.cc
index a6eec44..fd67bb4 100644
--- a/src/cobalt/xhr/url_fetcher_buffer_writer.cc
+++ b/src/cobalt/xhr/url_fetcher_buffer_writer.cc
@@ -28,6 +28,7 @@
const int64_t kDefaultPreAllocateSizeInBytes = 64 * 1024;
// Set max allocate size to avoid erroneous size estimate.
const int64_t kMaxPreAllocateSizeInBytes = 10 * 1024 * 1024;
+const uint8_t kResizingMultiplier = 2;
void ReleaseMemory(std::string* str) {
DCHECK(str);
@@ -167,6 +168,9 @@
} else {
capacity_known_ = true;
}
+ // Record the desired_capacity_ to avoid reserving unused memory during
+ // resizing.
+ desired_capacity_ = static_cast<size_t>(capacity);
if (capacity == 0) {
return;
@@ -218,7 +222,16 @@
SB_LOG(WARNING) << "Data written is larger than the preset capacity "
<< data_as_array_buffer_.byte_length();
}
- data_as_array_buffer_.Resize(data_as_array_buffer_size_ + num_bytes);
+ size_t new_size = std::max(
+ std::min(data_as_array_buffer_.byte_length() * kResizingMultiplier,
+ desired_capacity_),
+ data_as_array_buffer_size_ + num_bytes);
+ if (new_size > desired_capacity_) {
+ // Content-length is wrong, response size is completely unknown.
+ // Double the capacity to avoid frequent resizing.
+ new_size *= kResizingMultiplier;
+ }
+ data_as_array_buffer_.Resize(new_size);
}
auto destination = static_cast<uint8_t*>(data_as_array_buffer_.data()) +
diff --git a/src/cobalt/xhr/url_fetcher_buffer_writer.h b/src/cobalt/xhr/url_fetcher_buffer_writer.h
index 8eb9736..35058ab 100644
--- a/src/cobalt/xhr/url_fetcher_buffer_writer.h
+++ b/src/cobalt/xhr/url_fetcher_buffer_writer.h
@@ -74,6 +74,7 @@
Type type_;
bool allow_preallocate_ = true;
bool capacity_known_ = false;
+ size_t desired_capacity_ = 0;
// This class can be accessed by both network and MainWebModule threads.
mutable base::Lock lock_;
diff --git a/src/cobalt/xhr/xhr.gyp b/src/cobalt/xhr/xhr.gyp
index 051822e..c3ebc4c 100644
--- a/src/cobalt/xhr/xhr.gyp
+++ b/src/cobalt/xhr/xhr.gyp
@@ -23,8 +23,6 @@
'sources': [
'url_fetcher_buffer_writer.cc',
'url_fetcher_buffer_writer.h',
- 'xhr_response_data.cc',
- 'xhr_response_data.h',
'xml_http_request.cc',
'xml_http_request.h',
'xml_http_request_event_target.cc',
@@ -58,10 +56,10 @@
'target_name': 'xhr_test',
'type': '<(gtest_target_type)',
'sources': [
- 'xhr_response_data_test.cc',
'xml_http_request_test.cc',
],
'dependencies': [
+ '<@(cobalt_platform_dependencies)',
'<(DEPTH)/cobalt/base/base.gyp:base',
'<(DEPTH)/cobalt/dom/dom.gyp:dom',
'<(DEPTH)/testing/gmock.gyp:gmock',
diff --git a/src/cobalt/xhr/xhr_response_data.cc b/src/cobalt/xhr/xhr_response_data.cc
deleted file mode 100644
index d2e5051..0000000
--- a/src/cobalt/xhr/xhr_response_data.cc
+++ /dev/null
@@ -1,84 +0,0 @@
-// Copyright 2015 The Cobalt Authors. 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/xhr/xhr_response_data.h"
-
-#include <algorithm>
-
-#include "cobalt/dom/global_stats.h"
-
-namespace cobalt {
-namespace xhr {
-
-namespace {
-
-// When we don't have any data, we still want to return a non-null pointer to a
-// valid memory location. Because even it will never be accessed, a null
-// pointer may trigger undefined behavior in functions like memcpy. So we
-// create this dummy value here and return its address when we don't have any
-// data.
-uint8 s_dummy;
-
-// We are using std::string to store binary data so we want to ensure that char
-// occupies one byte.
-COMPILE_ASSERT(sizeof(char) == 1, char_should_occupy_one_byte);
-
-} // namespace
-
-XhrResponseData::XhrResponseData() { IncreaseMemoryUsage(); }
-
-XhrResponseData::~XhrResponseData() { DecreaseMemoryUsage(); }
-
-void XhrResponseData::Clear() {
- DecreaseMemoryUsage();
- // Use swap to force free the memory allocated.
- std::string dummy;
- data_.swap(dummy);
- IncreaseMemoryUsage();
-}
-
-void XhrResponseData::Reserve(size_t new_capacity_bytes) {
- DecreaseMemoryUsage();
- data_.reserve(new_capacity_bytes);
- IncreaseMemoryUsage();
-}
-
-void XhrResponseData::Append(const uint8* source_data, size_t size_bytes) {
- if (size_bytes == 0) {
- return;
- }
- DecreaseMemoryUsage();
- data_.resize(data_.size() + size_bytes);
- memcpy(&data_[data_.size() - size_bytes], source_data, size_bytes);
- IncreaseMemoryUsage();
-}
-
-const uint8* XhrResponseData::data() const {
- return data_.empty() ? &s_dummy : reinterpret_cast<const uint8*>(&data_[0]);
-}
-
-uint8* XhrResponseData::data() {
- return data_.empty() ? &s_dummy : reinterpret_cast<uint8*>(&data_[0]);
-}
-
-void XhrResponseData::IncreaseMemoryUsage() {
- dom::GlobalStats::GetInstance()->IncreaseXHRMemoryUsage(capacity());
-}
-
-void XhrResponseData::DecreaseMemoryUsage() {
- dom::GlobalStats::GetInstance()->DecreaseXHRMemoryUsage(capacity());
-}
-
-} // namespace xhr
-} // namespace cobalt
diff --git a/src/cobalt/xhr/xhr_response_data.h b/src/cobalt/xhr/xhr_response_data.h
deleted file mode 100644
index 894cd3f..0000000
--- a/src/cobalt/xhr/xhr_response_data.h
+++ /dev/null
@@ -1,57 +0,0 @@
-// Copyright 2015 The Cobalt Authors. 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_XHR_XHR_RESPONSE_DATA_H_
-#define COBALT_XHR_XHR_RESPONSE_DATA_H_
-
-#include <string>
-
-#include "base/basictypes.h"
-
-namespace cobalt {
-namespace xhr {
-
-// Simple wrapper for an array of data.
-// Used by XMLHttpRequest to construct the response body.
-class XhrResponseData {
- public:
- XhrResponseData();
- ~XhrResponseData();
-
- // Destroy the data_ and reset the size and capacity to 0.
- void Clear();
- // Allocate storage for |new_capacity_bytes| of data.
- void Reserve(size_t new_capacity_bytes);
- // Append |source_data|, |size_bytes| in length, to the data array.
- void Append(const uint8* source_data, size_t size_bytes);
-
- const uint8* data() const;
- uint8* data();
-
- const std::string& string() const { return data_; }
-
- size_t size() const { return data_.size(); }
- size_t capacity() const { return data_.capacity(); }
-
- private:
- void IncreaseMemoryUsage();
- void DecreaseMemoryUsage();
-
- std::string data_;
-};
-
-} // namespace xhr
-} // namespace cobalt
-
-#endif // COBALT_XHR_XHR_RESPONSE_DATA_H_
diff --git a/src/cobalt/xhr/xhr_response_data_test.cc b/src/cobalt/xhr/xhr_response_data_test.cc
deleted file mode 100644
index f63d70e..0000000
--- a/src/cobalt/xhr/xhr_response_data_test.cc
+++ /dev/null
@@ -1,55 +0,0 @@
-// Copyright 2015 The Cobalt Authors. 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/xhr/xhr_response_data.h"
-
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace cobalt {
-namespace xhr {
-
-namespace {
-
-TEST(XhrResponseData, InitialState) {
- XhrResponseData empty;
- EXPECT_EQ(0u, empty.size());
- EXPECT_TRUE(empty.data() != NULL);
-}
-
-TEST(XhrResponseData, Append) {
- XhrResponseData data;
- uint8 raw_data[64];
- for (int i = 0; i < 64; ++i) {
- raw_data[i] = static_cast<uint8>(i);
- }
- data.Append(raw_data, 64);
- EXPECT_EQ(64u, data.size());
- EXPECT_LE(64u, data.capacity());
-
- for (int i = 0; i < 64; ++i) {
- EXPECT_EQ(raw_data[i], data.data()[i]);
- }
-}
-
-TEST(XhrResponseData, Reserve) {
- XhrResponseData data;
- data.Reserve(1);
- EXPECT_LE(1u, data.capacity());
- EXPECT_EQ(0u, data.size());
- EXPECT_TRUE(data.data() != NULL);
-}
-
-} // namespace
-} // namespace xhr
-} // namespace cobalt
diff --git a/src/glimp/gles/context.cc b/src/glimp/gles/context.cc
index aa11665..21db890 100644
--- a/src/glimp/gles/context.cc
+++ b/src/glimp/gles/context.cc
@@ -1495,8 +1495,7 @@
// The incoming pixel data should be aligned as the client has specified
// that it will be.
- SB_DCHECK(nb::IsAligned(nb::AsInteger(pixels),
- static_cast<uintptr_t>(unpack_alignment_)));
+ SB_DCHECK(nb::IsAligned(pixels, static_cast<size_t>(unpack_alignment_)));
// Determine pitch taking into account glPixelStorei() settings.
int pitch_in_bytes = GetPitchForTextureData(width, pixel_format);
@@ -1578,8 +1577,7 @@
// The incoming pixel data should be aligned as the client has specified
// that it will be.
- SB_DCHECK(nb::IsAligned(nb::AsInteger(pixels),
- static_cast<uintptr_t>(unpack_alignment_)));
+ SB_DCHECK(nb::IsAligned(pixels, static_cast<size_t>(unpack_alignment_)));
// Determine pitch taking into account glPixelStorei() settings.
int pitch_in_bytes = GetPitchForTextureData(width, pixel_format);
diff --git a/src/nb/allocator.cc b/src/nb/allocator.cc
new file mode 100644
index 0000000..668c977
--- /dev/null
+++ b/src/nb/allocator.cc
@@ -0,0 +1,21 @@
+// Copyright 2020 The Cobalt Authors. 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 "nb/allocator.h"
+
+namespace nb {
+
+const size_t Allocator::kMinAlignment = 16;
+
+} // namespace nb
diff --git a/src/nb/allocator.h b/src/nb/allocator.h
index 07ee8e0..028e25d 100644
--- a/src/nb/allocator.h
+++ b/src/nb/allocator.h
@@ -17,9 +17,7 @@
#ifndef NB_ALLOCATOR_H_
#define NB_ALLOCATOR_H_
-// TODO: Include "starboard/types.h" once legacy platforms are ported to
-// starboard. Currently including <vector> is used as a platform independent
-// way to introduce std::size_t.
+#include <cstddef>
#include <vector>
namespace nb {
@@ -31,6 +29,11 @@
// through derived classes.
class Allocator {
public:
+ // Using a minimum value for alignment keeps things rounded and aligned
+ // and help us avoid creating tiny and/or badly misaligned free blocks. Also
+ // ensures even for a 0-byte request will get a unique block.
+ static const size_t kMinAlignment;
+
virtual ~Allocator() {}
// Allocates a range of memory of the given size, without any alignment
diff --git a/src/nb/analytics/memory_tracker.h b/src/nb/analytics/memory_tracker.h
index 182488a..cf6e0eb 100644
--- a/src/nb/analytics/memory_tracker.h
+++ b/src/nb/analytics/memory_tracker.h
@@ -32,8 +32,11 @@
class AllocationGroup;
struct MemoryStats {
- MemoryStats() : total_cpu_memory(0), used_cpu_memory(0),
- total_gpu_memory(0), used_gpu_memory(0) {}
+ MemoryStats()
+ : total_cpu_memory(0),
+ used_cpu_memory(0),
+ total_gpu_memory(0),
+ used_gpu_memory(0) {}
int64_t total_cpu_memory;
int64_t used_cpu_memory;
int64_t total_gpu_memory;
@@ -143,7 +146,8 @@
protected:
virtual ~MemoryTracker() {}
- SB_DISALLOW_COPY_AND_ASSIGN(MemoryTracker);
+ MemoryTracker(const MemoryTracker&) = delete;
+ void operator=(const MemoryTracker&) = delete;
};
// A visitor class which is useful for inspecting data.
diff --git a/src/nb/analytics/memory_tracker_helpers.h b/src/nb/analytics/memory_tracker_helpers.h
index 448b9ca..124bfaa 100644
--- a/src/nb/analytics/memory_tracker_helpers.h
+++ b/src/nb/analytics/memory_tracker_helpers.h
@@ -42,9 +42,7 @@
public:
NoReportAllocator() {}
NoReportAllocator(const NoReportAllocator&) {}
- static void* Allocate(size_t n) {
- return SbMemoryAllocateNoReport(n);
- }
+ static void* Allocate(size_t n) { return SbMemoryAllocateNoReport(n); }
// Second argument can be used for accounting, but is otherwise optional.
static void Deallocate(void* ptr, size_t /* not used*/) {
SbMemoryDeallocateNoReport(ptr);
@@ -73,7 +71,8 @@
starboard::atomic_int64_t allocation_bytes_;
starboard::atomic_int32_t num_allocations_;
- SB_DISALLOW_COPY_AND_ASSIGN(AllocationGroup);
+ AllocationGroup(const AllocationGroup&) = delete;
+ void operator=(const AllocationGroup&) = delete;
};
// A self locking data structure that maps strings -> AllocationGroups. This is
@@ -96,14 +95,16 @@
std::string,
AllocationGroup*,
std::less<std::string>,
- nb::StdAllocator<
- std::pair<const std::string, AllocationGroup*>,
- NoReportAllocator> > Map;
+ nb::StdAllocator<std::pair<const std::string, AllocationGroup*>,
+ NoReportAllocator> >
+ Map;
Map group_map_;
AllocationGroup* unaccounted_group_;
mutable starboard::Mutex mutex_;
- SB_DISALLOW_COPY_AND_ASSIGN(AtomicStringAllocationGroupMap);
+ AtomicStringAllocationGroupMap(const AtomicStringAllocationGroupMap&) =
+ delete;
+ void operator=(const AtomicStringAllocationGroupMap&) = delete;
};
class AllocationGroupStack {
@@ -127,7 +128,9 @@
const AllocationGroupPtrVec& data() const { return alloc_group_stack_; }
private:
- SB_DISALLOW_COPY_AND_ASSIGN(AllocationGroupStack);
+ AllocationGroupStack(const AllocationGroupStack&) = delete;
+ void operator=(const AllocationGroupStack&) = delete;
+
AllocationGroupPtrVec alloc_group_stack_, debug_stack_;
};
@@ -161,14 +164,15 @@
const void*,
AllocationRecord,
std::less<const void*>, // required, when specifying allocator.
- nb::StdAllocator<
- std::pair<const void* const, AllocationRecord>,
- NoReportAllocator> > PointerMap;
+ nb::StdAllocator<std::pair<const void* const, AllocationRecord>,
+ NoReportAllocator> >
+ PointerMap;
PointerMap pointer_map_;
mutable starboard::Mutex mutex_;
- SB_DISALLOW_COPY_AND_ASSIGN(AtomicAllocationMap);
+ AtomicAllocationMap(const AtomicAllocationMap&) = delete;
+ void operator=(const AtomicAllocationMap&) = delete;
};
// A per-pointer map of allocations to AllocRecords. This is a hybrid data
@@ -203,7 +207,9 @@
const AtomicAllocationMap& GetMapForPointer(const void* ptr) const;
private:
- SB_DISALLOW_COPY_AND_ASSIGN(ConcurrentAllocationMap);
+ ConcurrentAllocationMap(const ConcurrentAllocationMap&) = delete;
+ void operator=(const ConcurrentAllocationMap&) = delete;
+
// Takes a pointer and generates a hash.
static uint32_t hash_ptr(const void* ptr);
diff --git a/src/nb/bidirectional_fit_reuse_allocator_test.cc b/src/nb/bidirectional_fit_reuse_allocator_test.cc
index 6c08b9b..21d841a 100644
--- a/src/nb/bidirectional_fit_reuse_allocator_test.cc
+++ b/src/nb/bidirectional_fit_reuse_allocator_test.cc
@@ -17,18 +17,15 @@
#include "nb/bidirectional_fit_reuse_allocator.h"
#include "nb/fixed_no_free_allocator.h"
+#include "nb/pointer_arithmetic.h"
#include "nb/scoped_ptr.h"
+#include "nb/starboard_aligned_memory_deleter.h"
#include "starboard/configuration.h"
#include "starboard/types.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace {
-inline bool IsAligned(void* ptr, std::size_t boundary) {
- uintptr_t ptr_as_int = reinterpret_cast<uintptr_t>(ptr);
- return ptr_as_int % boundary == 0;
-}
-
class BidirectionalFitReuseAllocatorTest : public ::testing::Test {
public:
static const int kBufferSize = 1 * 1024 * 1024;
@@ -39,18 +36,19 @@
void ResetAllocator(std::size_t initial_capacity = 0,
std::size_t small_allocation_threshold = 0,
std::size_t allocation_increment = 0) {
- nb::scoped_array<uint8_t> buffer(new uint8_t[kBufferSize]);
+ buffer_.reset(static_cast<uint8_t*>(
+ SbMemoryAllocateAligned(nb::Allocator::kMinAlignment, kBufferSize)));
+
nb::scoped_ptr<nb::FixedNoFreeAllocator> fallback_allocator(
- new nb::FixedNoFreeAllocator(buffer.get(), kBufferSize));
+ new nb::FixedNoFreeAllocator(buffer_.get(), kBufferSize));
allocator_.reset(new nb::BidirectionalFitReuseAllocator(
fallback_allocator.get(), initial_capacity, small_allocation_threshold,
allocation_increment));
fallback_allocator_.swap(fallback_allocator);
- buffer_.swap(buffer);
}
- nb::scoped_array<uint8_t> buffer_;
+ std::unique_ptr<uint8_t, nb::AlignedMemoryDeleter> buffer_;
nb::scoped_ptr<nb::FixedNoFreeAllocator> fallback_allocator_;
nb::scoped_ptr<nb::BidirectionalFitReuseAllocator> allocator_;
};
@@ -64,7 +62,7 @@
for (int j = 0; j < SB_ARRAY_SIZE(kBlockSizes); ++j) {
void* p = allocator_->Allocate(kBlockSizes[j], kAlignments[i]);
EXPECT_TRUE(p != NULL);
- EXPECT_EQ(IsAligned(p, kAlignments[i]), true);
+ EXPECT_EQ(nb::IsAligned(p, kAlignments[i]), true);
allocator_->Free(p);
}
}
diff --git a/src/nb/concurrent_map.h b/src/nb/concurrent_map.h
index 39e2b4e..c066872 100644
--- a/src/nb/concurrent_map.h
+++ b/src/nb/concurrent_map.h
@@ -299,7 +299,8 @@
typename InnerMap::iterator iterator_;
bool iterator_valid_;
- SB_DISALLOW_COPY_AND_ASSIGN(EntryHandle);
+ EntryHandle(const EntryHandle&) = delete;
+ void operator=(const EntryHandle&) = delete;
};
class ConstEntryHandle {
@@ -349,7 +350,8 @@
typename InnerMap::const_iterator iterator_;
bool iterator_valid_;
- SB_DISALLOW_COPY_AND_ASSIGN(ConstEntryHandle);
+ ConstEntryHandle(const ConstEntryHandle&) = delete;
+ void operator=(const ConstEntryHandle&) = delete;
};
struct Bucket {
diff --git a/src/nb/first_fit_reuse_allocator_test.cc b/src/nb/first_fit_reuse_allocator_test.cc
index 2e51bd2..dd70c6d 100644
--- a/src/nb/first_fit_reuse_allocator_test.cc
+++ b/src/nb/first_fit_reuse_allocator_test.cc
@@ -17,18 +17,15 @@
#include "nb/first_fit_reuse_allocator.h"
#include "nb/fixed_no_free_allocator.h"
+#include "nb/pointer_arithmetic.h"
#include "nb/scoped_ptr.h"
+#include "nb/starboard_aligned_memory_deleter.h"
#include "starboard/configuration.h"
#include "starboard/types.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace {
-inline bool IsAligned(void* ptr, std::size_t boundary) {
- uintptr_t ptr_as_int = reinterpret_cast<uintptr_t>(ptr);
- return ptr_as_int % boundary == 0;
-}
-
class FirstFitReuseAllocatorTest : public ::testing::Test {
public:
static const int kBufferSize = 1 * 1024 * 1024;
@@ -38,17 +35,17 @@
protected:
void ResetAllocator(std::size_t initial_capacity = 0,
std::size_t allocation_increment = 0) {
- nb::scoped_array<uint8_t> buffer(new uint8_t[kBufferSize]);
+ buffer_.reset(static_cast<uint8_t*>(
+ SbMemoryAllocateAligned(nb::Allocator::kMinAlignment, kBufferSize)));
nb::scoped_ptr<nb::FixedNoFreeAllocator> fallback_allocator(
- new nb::FixedNoFreeAllocator(buffer.get(), kBufferSize));
+ new nb::FixedNoFreeAllocator(buffer_.get(), kBufferSize));
allocator_.reset(new nb::FirstFitReuseAllocator(
fallback_allocator.get(), initial_capacity, allocation_increment));
fallback_allocator_.swap(fallback_allocator);
- buffer_.swap(buffer);
}
- nb::scoped_array<uint8_t> buffer_;
+ std::unique_ptr<uint8_t, nb::AlignedMemoryDeleter> buffer_;
nb::scoped_ptr<nb::FixedNoFreeAllocator> fallback_allocator_;
nb::scoped_ptr<nb::FirstFitReuseAllocator> allocator_;
};
@@ -62,7 +59,7 @@
for (int j = 0; j < SB_ARRAY_SIZE(kBlockSizes); ++j) {
void* p = allocator_->Allocate(kBlockSizes[j], kAlignments[i]);
EXPECT_TRUE(p != NULL);
- EXPECT_EQ(IsAligned(p, kAlignments[i]), true);
+ EXPECT_EQ(nb::IsAligned(p, kAlignments[i]), true);
allocator_->Free(p);
}
}
diff --git a/src/nb/fixed_no_free_allocator.cc b/src/nb/fixed_no_free_allocator.cc
index f4f8e1c..c7fa52a 100644
--- a/src/nb/fixed_no_free_allocator.cc
+++ b/src/nb/fixed_no_free_allocator.cc
@@ -25,6 +25,7 @@
std::size_t memory_size)
: memory_start_(memory_start),
memory_end_(AsPointer(AsInteger(memory_start) + memory_size)) {
+ SB_CHECK(IsAligned(memory_start, kMinAlignment));
next_memory_ = memory_start_;
}
diff --git a/src/nb/fixed_no_free_allocator.h b/src/nb/fixed_no_free_allocator.h
index 31bfc60..b2c53f7 100644
--- a/src/nb/fixed_no_free_allocator.h
+++ b/src/nb/fixed_no_free_allocator.h
@@ -36,6 +36,7 @@
// memory and we would like to wrap it in an allocator.
class FixedNoFreeAllocator : public Allocator {
public:
+ // Requires aligned memory to at least |nb::kMinAlignment|.
FixedNoFreeAllocator(void* memory_start, std::size_t memory_size);
void* Allocate(std::size_t size) { return Allocate(&size, 1, true); }
diff --git a/src/nb/fixed_no_free_allocator_test.cc b/src/nb/fixed_no_free_allocator_test.cc
index 89b4545..5789fb9 100644
--- a/src/nb/fixed_no_free_allocator_test.cc
+++ b/src/nb/fixed_no_free_allocator_test.cc
@@ -17,6 +17,7 @@
#include "nb/fixed_no_free_allocator.h"
#include "nb/pointer_arithmetic.h"
+#include "nb/starboard_aligned_memory_deleter.h"
#include "testing/gtest/include/gtest/gtest.h"
class FixedNoFreeAllocatorTest : public ::testing::Test {
@@ -29,30 +30,32 @@
static const std::size_t kMaxAllocations = 64;
static const std::size_t kBufferSize = kAllocationSize * kMaxAllocations;
- char buffer_[kBufferSize];
+ std::unique_ptr<uint8_t, nb::AlignedMemoryDeleter> buffer_;
nb::FixedNoFreeAllocator allocator_;
};
FixedNoFreeAllocatorTest::FixedNoFreeAllocatorTest()
- : allocator_(buffer_, kBufferSize) {}
+ : buffer_(static_cast<uint8_t*>(
+ SbMemoryAllocateAligned(nb::Allocator::kMinAlignment, kBufferSize))),
+ allocator_(buffer_.get(), kBufferSize) {}
TEST_F(FixedNoFreeAllocatorTest, CanDoSimpleAllocations) {
void* allocation = allocator_.Allocate(kAllocationSize);
- EXPECT_GE(allocation, buffer_);
- EXPECT_LE(
- reinterpret_cast<uintptr_t>(allocation),
- reinterpret_cast<uintptr_t>(buffer_) + kBufferSize - kAllocationSize);
+ EXPECT_GE(allocation, buffer_.get());
+ EXPECT_LE(reinterpret_cast<uintptr_t>(allocation),
+ reinterpret_cast<uintptr_t>(buffer_.get()) + kBufferSize -
+ kAllocationSize);
}
TEST_F(FixedNoFreeAllocatorTest, CanDoMultipleAllocationsProperly) {
void* buffers[kMaxAllocations];
for (int i = 0; i < kMaxAllocations; ++i) {
buffers[i] = allocator_.Allocate(kAllocationSize);
- EXPECT_GE(buffers[i], buffer_);
- EXPECT_LE(
- reinterpret_cast<uintptr_t>(buffers[i]),
- reinterpret_cast<uintptr_t>(buffer_) + kBufferSize - kAllocationSize);
+ EXPECT_GE(buffers[i], buffer_.get());
+ EXPECT_LE(reinterpret_cast<uintptr_t>(buffers[i]),
+ reinterpret_cast<uintptr_t>(buffer_.get()) + kBufferSize -
+ kAllocationSize);
// Make sure this allocation doesn't overlap with any previous ones.
for (int j = 0; j < i; ++j) {
@@ -72,10 +75,10 @@
for (int i = 0; i < kMaxAllocations; ++i) {
void* current_allocation = allocator_.Allocate(kAllocationSize);
- EXPECT_GE(current_allocation, buffer_);
- EXPECT_LE(
- reinterpret_cast<uintptr_t>(current_allocation),
- reinterpret_cast<uintptr_t>(buffer_) + kBufferSize - kAllocationSize);
+ EXPECT_GE(current_allocation, buffer_.get());
+ EXPECT_LE(reinterpret_cast<uintptr_t>(current_allocation),
+ reinterpret_cast<uintptr_t>(buffer_.get()) + kBufferSize -
+ kAllocationSize);
allocator_.Free(current_allocation);
}
@@ -85,10 +88,10 @@
for (int i = 0; i < kMaxAllocations; ++i) {
void* current_allocation = allocator_.Allocate(kAllocationSize);
- EXPECT_GE(current_allocation, buffer_);
- EXPECT_LE(
- reinterpret_cast<uintptr_t>(current_allocation),
- reinterpret_cast<uintptr_t>(buffer_) + kBufferSize - kAllocationSize);
+ EXPECT_GE(current_allocation, buffer_.get());
+ EXPECT_LE(reinterpret_cast<uintptr_t>(current_allocation),
+ reinterpret_cast<uintptr_t>(buffer_.get()) + kBufferSize -
+ kAllocationSize);
allocator_.Free(current_allocation);
}
@@ -109,10 +112,10 @@
EXPECT_EQ(0, reinterpret_cast<uintptr_t>(current_allocation) %
kAllocationAlignment);
- EXPECT_GE(current_allocation, buffer_);
- EXPECT_LE(
- reinterpret_cast<uintptr_t>(current_allocation),
- reinterpret_cast<uintptr_t>(buffer_) + kBufferSize - kAllocationSize);
+ EXPECT_GE(current_allocation, buffer_.get());
+ EXPECT_LE(reinterpret_cast<uintptr_t>(current_allocation),
+ reinterpret_cast<uintptr_t>(buffer_.get()) + kBufferSize -
+ kAllocationSize);
allocator_.Free(current_allocation);
}
diff --git a/src/nb/nb.gyp b/src/nb/nb.gyp
index ce9e71d..6078f07 100644
--- a/src/nb/nb.gyp
+++ b/src/nb/nb.gyp
@@ -36,6 +36,7 @@
'conditions': [
['OS=="starboard"', {
'sources': [
+ 'allocator.cc',
'allocator.h',
'analytics/memory_tracker.cc',
'analytics/memory_tracker.h',
@@ -75,6 +76,7 @@
'simple_thread.h',
'simple_profiler.cc',
'simple_profiler.h',
+ 'starboard_aligned_memory_deleter.h',
'std_allocator.h',
'string_interner.cc',
'string_interner.h',
diff --git a/src/nb/pointer_arithmetic.h b/src/nb/pointer_arithmetic.h
index cb1539a..d34cba0 100644
--- a/src/nb/pointer_arithmetic.h
+++ b/src/nb/pointer_arithmetic.h
@@ -61,8 +61,8 @@
// Helper method for subclasses to determine if a given address or value
// is aligned or not.
template <typename T>
-static bool IsAligned(T value, T alignment) {
- return value % alignment == 0;
+static bool IsAligned(T value, size_t alignment) {
+ return AsInteger(value) % alignment == 0;
}
} // namespace nb
diff --git a/src/nb/reuse_allocator_base.cc b/src/nb/reuse_allocator_base.cc
index 95189ac..2d6943a 100644
--- a/src/nb/reuse_allocator_base.cc
+++ b/src/nb/reuse_allocator_base.cc
@@ -29,10 +29,6 @@
// Minimum block size to avoid extremely small blocks inside the block list and
// to ensure that a zero sized allocation will return a non-zero sized block.
const std::size_t kMinBlockSizeBytes = 16;
-// Using a minimum value for size and alignment keeps things rounded and aligned
-// and help us avoid creating tiny and/or badly misaligned free blocks. Also
-// ensures even for a 0-byte request will get a unique block.
-const std::size_t kMinAlignment = 16;
// The max lines of allocation to print inside PrintAllocations(). Set to 0 to
// print all allocations.
const int kMaxAllocationLinesToPrint = 0;
diff --git a/src/nb/simple_thread.h b/src/nb/simple_thread.h
index b01a58c..1f9132d 100644
--- a/src/nb/simple_thread.h
+++ b/src/nb/simple_thread.h
@@ -56,7 +56,8 @@
SbThread thread_;
starboard::atomic_bool join_called_;
- SB_DISALLOW_COPY_AND_ASSIGN(SimpleThread);
+ SimpleThread(const SimpleThread&) = delete;
+ void operator=(const SimpleThread&) = delete;
};
} // namespace nb
diff --git a/src/nb/starboard_aligned_memory_deleter.h b/src/nb/starboard_aligned_memory_deleter.h
new file mode 100644
index 0000000..4f307c1
--- /dev/null
+++ b/src/nb/starboard_aligned_memory_deleter.h
@@ -0,0 +1,28 @@
+// Copyright 2020 The Cobalt Authors. 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 NB_STARBOARD_ALIGNED_MEMORY_DELETER_H_
+#define NB_STARBOARD_ALIGNED_MEMORY_DELETER_H_
+
+#include "starboard/memory.h"
+
+namespace nb {
+
+struct AlignedMemoryDeleter {
+ void operator()(uint8_t* p) { SbMemoryDeallocateAligned(p); }
+};
+
+} // namespace nb
+
+#endif // NB_STARBOARD_ALIGNED_MEMORY_DELETER_H_
diff --git a/src/nb/string_interner.h b/src/nb/string_interner.h
index e739b69..f842449 100644
--- a/src/nb/string_interner.h
+++ b/src/nb/string_interner.h
@@ -65,13 +65,15 @@
mutable starboard::Mutex mutex_;
mutable std::string scratch_;
- SB_DISALLOW_COPY_AND_ASSIGN(StringInterner);
+ StringInterner(const StringInterner&) = delete;
+ void operator=(const StringInterner&) = delete;
};
class ConcurrentStringInterner {
public:
explicit ConcurrentStringInterner(size_t table_size = 32);
- ~ConcurrentStringInterner(); // All outstanding const std::string* are invalidated.
+ ~ConcurrentStringInterner(); // All outstanding const std::string* are
+ // invalidated.
// Returns an equivalent string to the input. If the input is missing from
// the data store then a copy-by-value is made.
@@ -90,7 +92,8 @@
const StringInterner& GetBucket(const char* string, size_t n) const;
std::vector<StringInterner*> string_interner_table_;
- SB_DISALLOW_COPY_AND_ASSIGN(ConcurrentStringInterner);
+ ConcurrentStringInterner(const ConcurrentStringInterner&) = delete;
+ void operator=(const ConcurrentStringInterner&) = delete;
};
} // namespace nb
diff --git a/src/nb/test_thread.h b/src/nb/test_thread.h
index 0ea5768..4f2da5d 100644
--- a/src/nb/test_thread.h
+++ b/src/nb/test_thread.h
@@ -35,14 +35,11 @@
void Start() {
SbThreadEntryPoint entry_point = ThreadEntryPoint;
- thread_ = SbThreadCreate(
- 0, // default stack_size.
- kSbThreadNoPriority, // default priority.
- kSbThreadNoAffinity, // default affinity.
- true, // joinable.
- "TestThread",
- entry_point,
- this);
+ thread_ = SbThreadCreate(0, // default stack_size.
+ kSbThreadNoPriority, // default priority.
+ kSbThreadNoAffinity, // default affinity.
+ true, // joinable.
+ "TestThread", entry_point, this);
if (kSbThreadInvalid == thread_) {
ADD_FAILURE_AT(__FILE__, __LINE__) << "Invalid thread.";
@@ -65,7 +62,8 @@
SbThread thread_;
- SB_DISALLOW_COPY_AND_ASSIGN(TestThread);
+ TestThread(const TestThread&) = delete;
+ void operator=(const TestThread&) = delete;
};
} // namespace nb.
diff --git a/src/nb/thread_local_boolean.h b/src/nb/thread_local_boolean.h
index d91a744..c27baf6 100644
--- a/src/nb/thread_local_boolean.h
+++ b/src/nb/thread_local_boolean.h
@@ -44,7 +44,8 @@
ThreadLocalPointer<void> tlp_;
const bool default_value_;
- SB_DISALLOW_COPY_AND_ASSIGN(ThreadLocalBoolean);
+ ThreadLocalBoolean(const ThreadLocalBoolean&) = delete;
+ void operator=(const ThreadLocalBoolean&) = delete;
};
} // namespace nb.
diff --git a/src/nb/thread_local_object.h b/src/nb/thread_local_object.h
index 6299f51..741227f 100644
--- a/src/nb/thread_local_object.h
+++ b/src/nb/thread_local_object.h
@@ -77,11 +77,11 @@
CheckCurrentThreadAllowedToDestruct();
if (SB_DLOG_IS_ON(FATAL)) {
SB_DCHECK(entry_set_.size() < 2)
- << "Logic error: Some threads may still be accessing the objects that "
- << "are about to be destroyed. Only one object is expected and that "
- << "should be for the main thread. The caller should ensure that "
- << "other threads that access this object are externally "
- << "synchronized.";
+ << "Logic error: Some threads may still be accessing the objects "
+ << "that are about to be destroyed. Only one object is expected "
+ << "and that should be for the main thread. The caller should "
+ << "ensure that other threads that access this object are"
+ << " externally synchronized.";
}
// No locking is done because the entries should not be accessed by
// different threads while this object is shutting down. If access is
@@ -101,20 +101,20 @@
// Warns if there is a misuse of this object.
void CheckCurrentThreadAllowedToDestruct() const {
if (kSbThreadInvalidId == constructing_thread_id_) {
- return; // EnableDestructionByAnyThread() called.
+ return; // EnableDestructionByAnyThread() called.
}
const SbThreadId curr_thread_id = SbThreadGetId();
if (curr_thread_id == constructing_thread_id_) {
- return; // Same thread that constructed this.
+ return; // Same thread that constructed this.
}
if (SB_DLOG_IS_ON(FATAL)) {
- SB_DCHECK(false)
- << "ThreadLocalObject<T> was created in thread "
- << constructing_thread_id_ << "\nbut was destroyed by "
- << curr_thread_id << ". If this is intentional then call "
- << "EnableDestructionByAnyThread() to silence this "
- << "warning.";
+ SB_DCHECK(false) << "ThreadLocalObject<T> was created in thread "
+ << constructing_thread_id_ << "\nbut was destroyed by "
+ << curr_thread_id
+ << ". If this is intentional then call "
+ << "EnableDestructionByAnyThread() to silence this "
+ << "warning.";
}
}
@@ -158,7 +158,9 @@
// Returns the pointer if it exists in the current thread, otherwise NULL.
Type* GetIfExists() const {
Entry* entry = GetEntryIfExists();
- if (!entry) { return NULL; }
+ if (!entry) {
+ return NULL;
+ }
return entry->ptr_;
}
@@ -178,8 +180,7 @@
private:
struct Entry {
- Entry(ThreadLocalObject* own, Type* ptr) : owner_(own), ptr_(ptr) {
- }
+ Entry(ThreadLocalObject* own, Type* ptr) : owner_(own), ptr_(ptr) {}
~Entry() {
ptr_ = NULL;
owner_ = NULL;
@@ -228,7 +229,8 @@
// thread that destroyed this object.
SbThreadId constructing_thread_id_;
- SB_DISALLOW_COPY_AND_ASSIGN(ThreadLocalObject<Type>);
+ ThreadLocalObject<Type>(const ThreadLocalObject<Type>&) = delete;
+ void operator=(const ThreadLocalObject<Type>&) = delete;
};
} // namespace nb
diff --git a/src/nb/thread_local_pointer.h b/src/nb/thread_local_pointer.h
index d21f81f..5d0e7f3 100644
--- a/src/nb/thread_local_pointer.h
+++ b/src/nb/thread_local_pointer.h
@@ -46,7 +46,8 @@
private:
SbThreadLocalKey slot_;
- SB_DISALLOW_COPY_AND_ASSIGN(ThreadLocalPointer<Type>);
+ ThreadLocalPointer<Type>(const ThreadLocalPointer<Type>&) = delete;
+ void operator=(const ThreadLocalPointer<Type>&) = delete;
};
} // namespace nb.
diff --git a/src/starboard/android/apk/app/src/main/java/dev/cobalt/coat/CobaltActivity.java b/src/starboard/android/apk/app/src/main/java/dev/cobalt/coat/CobaltActivity.java
index ac9be3c..89b4be8 100644
--- a/src/starboard/android/apk/app/src/main/java/dev/cobalt/coat/CobaltActivity.java
+++ b/src/starboard/android/apk/app/src/main/java/dev/cobalt/coat/CobaltActivity.java
@@ -27,6 +27,7 @@
import android.view.ViewGroup.LayoutParams;
import android.view.ViewParent;
import android.widget.FrameLayout;
+import dev.cobalt.media.MediaCodecUtil;
import dev.cobalt.media.VideoSurfaceView;
import dev.cobalt.util.Log;
import dev.cobalt.util.UsedByNative;
@@ -45,7 +46,9 @@
private static final java.lang.String META_DATA_APP_URL = "cobalt.APP_URL";
private static final String SPLASH_URL_ARG = "--fallback_splash_screen_url=";
+ private static final String SPLASH_TOPICS_ARG = "--fallback_splash_screen_topics=";
private static final java.lang.String META_DATA_SPLASH_URL = "cobalt.SPLASH_URL";
+ private static final java.lang.String META_DATA_SPLASH_TOPICS = "cobalt.SPLASH_TOPIC";
private static final String FORCE_MIGRATION_FOR_STORAGE_PARTITIONING =
"--force_migration_for_storage_partitioning";
@@ -107,6 +110,9 @@
@Override
protected void onStart() {
+ if (!isReleaseBuild()) {
+ MediaCodecUtil.dumpAllDecoders();
+ }
if (forceCreateNewVideoSurfaceView) {
Log.w(TAG, "Force to create a new video surface.");
createNewSurfaceView();
@@ -174,7 +180,9 @@
boolean hasUrlArg = hasArg(args, URL_ARG);
// If the splash screen url arg isn't specified, get it from AndroidManifest.xml.
boolean hasSplashUrlArg = hasArg(args, SPLASH_URL_ARG);
- if (!hasUrlArg || !hasSplashUrlArg) {
+ // If the splash screen topics arg isn't specified, get it from AndroidManifest.xml.
+ boolean hasSplashTopicsArg = hasArg(args, SPLASH_TOPICS_ARG);
+ if (!hasUrlArg || !hasSplashUrlArg || !hasSplashTopicsArg) {
try {
ActivityInfo ai =
getPackageManager()
@@ -192,6 +200,12 @@
args.add(SPLASH_URL_ARG + splashUrl);
}
}
+ if (!hasSplashTopicsArg) {
+ String splashTopics = ai.metaData.getString(META_DATA_SPLASH_TOPICS);
+ if (splashTopics != null) {
+ args.add(SPLASH_TOPICS_ARG + splashTopics);
+ }
+ }
if (ai.metaData.getBoolean(META_FORCE_MIGRATION_FOR_STORAGE_PARTITIONING)) {
args.add(FORCE_MIGRATION_FOR_STORAGE_PARTITIONING);
}
diff --git a/src/starboard/android/apk/app/src/main/java/dev/cobalt/coat/MediaPlaybackService.java b/src/starboard/android/apk/app/src/main/java/dev/cobalt/coat/MediaPlaybackService.java
index 2fb2c95..b6de9b0 100644
--- a/src/starboard/android/apk/app/src/main/java/dev/cobalt/coat/MediaPlaybackService.java
+++ b/src/starboard/android/apk/app/src/main/java/dev/cobalt/coat/MediaPlaybackService.java
@@ -41,6 +41,10 @@
public void onCreate() {
super.onCreate();
Log.i(TAG, "Creating a Media playback foreground service.");
+ if (getStarboardBridge() == null) {
+ Log.e(TAG, "StarboardBridge already destroyed.");
+ return;
+ }
getStarboardBridge().onServiceStart(this);
context = getApplicationContext();
}
@@ -61,10 +65,14 @@
@Override
public void onDestroy() {
+ if (getStarboardBridge() == null) {
+ Log.e(TAG, "StarboardBridge already destroyed.");
+ return;
+ }
getStarboardBridge().onServiceDestroy(this);
context = null;
super.onDestroy();
- Log.i(TAG, "Destorying the Media playback service.");
+ Log.i(TAG, "Destroying the Media playback service.");
}
public void startService() {
@@ -139,6 +147,10 @@
@UsedByNative
protected StarboardBridge getStarboardBridge() {
+ if (getApplication() == null) {
+ Log.e(TAG, "Application already destroyed.");
+ return null;
+ }
return ((StarboardBridge.HostApplication) getApplication()).getStarboardBridge();
}
diff --git a/src/starboard/android/apk/app/src/main/java/dev/cobalt/coat/VoiceRecognizer.java b/src/starboard/android/apk/app/src/main/java/dev/cobalt/coat/VoiceRecognizer.java
index 06cc02f..799aef9 100644
--- a/src/starboard/android/apk/app/src/main/java/dev/cobalt/coat/VoiceRecognizer.java
+++ b/src/starboard/android/apk/app/src/main/java/dev/cobalt/coat/VoiceRecognizer.java
@@ -122,7 +122,8 @@
this.nativeSpeechRecognizerImpl = nativeSpeechRecognizer;
if (this.audioPermissionRequester.requestRecordAudioPermission(
- this.nativeSpeechRecognizerImpl)) {
+ this.nativeSpeechRecognizerImpl) &&
+ SpeechRecognizer.isRecognitionAvailable(context)) {
startRecognitionInternal();
} else {
mainHandler.post(
diff --git a/src/starboard/android/apk/app/src/main/java/dev/cobalt/media/AudioOutputManager.java b/src/starboard/android/apk/app/src/main/java/dev/cobalt/media/AudioOutputManager.java
index 554d8d5..b80fa03 100644
--- a/src/starboard/android/apk/app/src/main/java/dev/cobalt/media/AudioOutputManager.java
+++ b/src/starboard/android/apk/app/src/main/java/dev/cobalt/media/AudioOutputManager.java
@@ -48,9 +48,18 @@
@SuppressWarnings("unused")
@UsedByNative
AudioTrackBridge createAudioTrackBridge(
- int sampleType, int sampleRate, int channelCount, int preferredBufferSizeInBytes) {
+ int sampleType,
+ int sampleRate,
+ int channelCount,
+ int preferredBufferSizeInBytes,
+ int tunnelModeAudioSessionId) {
AudioTrackBridge audioTrackBridge =
- new AudioTrackBridge(sampleType, sampleRate, channelCount, preferredBufferSizeInBytes);
+ new AudioTrackBridge(
+ sampleType,
+ sampleRate,
+ channelCount,
+ preferredBufferSizeInBytes,
+ tunnelModeAudioSessionId);
if (!audioTrackBridge.isAudioTrackValid()) {
Log.e(TAG, "AudioTrackBridge has invalid audio track");
return null;
@@ -128,4 +137,29 @@
}
return AudioTrack.getMinBufferSize(sampleRate, channelConfig, sampleType);
}
+
+ /** Generate audio session id used by tunneled playback. */
+ @SuppressWarnings("unused")
+ @UsedByNative
+ int generateTunnelModeAudioSessionId(int numberOfChannels) {
+ // Android 9.0 (Build.VERSION.SDK_INT >= 28) support v2 sync header that
+ // aligns sync header with audio frame size. V1 sync header has alignment
+ // issues for multi-channel audio.
+ if (Build.VERSION.SDK_INT < 28) {
+ // Currently we only support int16 under tunnel mode.
+ final int sampleSizeInBytes = 2;
+ final int frameSizeInBytes = sampleSizeInBytes * numberOfChannels;
+ if (AudioTrackBridge.AV_SYNC_HEADER_V1_SIZE % frameSizeInBytes != 0) {
+ Log.w(
+ TAG,
+ String.format(
+ "Disable tunnel mode due to sampleSizeInBytes (%d) * numberOfChannels (%d) isn't"
+ + " aligned to AV_SYNC_HEADER_V1_SIZE (%d).",
+ sampleSizeInBytes, numberOfChannels, AudioTrackBridge.AV_SYNC_HEADER_V1_SIZE));
+ return -1;
+ }
+ }
+ AudioManager audioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
+ return audioManager.generateAudioSessionId();
+ }
}
diff --git a/src/starboard/android/apk/app/src/main/java/dev/cobalt/media/AudioTrackBridge.java b/src/starboard/android/apk/app/src/main/java/dev/cobalt/media/AudioTrackBridge.java
index 419f5d8..b8d5a53 100644
--- a/src/starboard/android/apk/app/src/main/java/dev/cobalt/media/AudioTrackBridge.java
+++ b/src/starboard/android/apk/app/src/main/java/dev/cobalt/media/AudioTrackBridge.java
@@ -26,18 +26,45 @@
import dev.cobalt.util.Log;
import dev.cobalt.util.UsedByNative;
import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
-// A wrapper of the android AudioTrack class.
-// Android AudioTrack would not start playing until the buffer is fully
-// filled once.
+/**
+ * A wrapper of the android AudioTrack class. Android AudioTrack would not start playing until the
+ * buffer is fully filled once.
+ */
@UsedByNative
public class AudioTrackBridge {
+ // Also used by AudioOutputManager.
+ static final int AV_SYNC_HEADER_V1_SIZE = 16;
+
private AudioTrack audioTrack;
private AudioTimestamp audioTimestamp = new AudioTimestamp();
private long maxFramePositionSoFar = 0;
+ private final boolean tunnelModeEnabled;
+ // The following variables are used only when |tunnelModeEnabled| is true.
+ private ByteBuffer avSyncHeader;
+ private int avSyncPacketBytesRemaining;
+
+ private static int getBytesPerSample(int audioFormat) {
+ switch (audioFormat) {
+ case AudioFormat.ENCODING_PCM_16BIT:
+ return 2;
+ case AudioFormat.ENCODING_PCM_FLOAT:
+ return 4;
+ case AudioFormat.ENCODING_INVALID:
+ default:
+ throw new RuntimeException("Unsupport audio format " + audioFormat);
+ }
+ }
+
public AudioTrackBridge(
- int sampleType, int sampleRate, int channelCount, int preferredBufferSizeInBytes) {
+ int sampleType,
+ int sampleRate,
+ int channelCount,
+ int preferredBufferSizeInBytes,
+ int tunnelModeAudioSessionId) {
+ tunnelModeEnabled = tunnelModeAudioSessionId != -1;
int channelConfig;
switch (channelCount) {
case 1:
@@ -53,11 +80,40 @@
throw new RuntimeException("Unsupported channel count: " + channelCount);
}
- AudioAttributes attributes =
- new AudioAttributes.Builder()
- .setContentType(AudioAttributes.CONTENT_TYPE_MUSIC)
- .setUsage(AudioAttributes.USAGE_MEDIA)
- .build();
+ AudioAttributes attributes;
+ if (tunnelModeEnabled) {
+ // Android 9.0 (Build.VERSION.SDK_INT >= 28) support v2 sync header that aligns sync header
+ // with audio frame size. V1 sync header has alignment issues for multi-channel audio.
+ if (Build.VERSION.SDK_INT < 28) {
+ int frameSize = getBytesPerSample(sampleType) * channelCount;
+ // This shouldn't happen as it should have been checked in
+ // AudioOutputManager.generateTunnelModeAudioSessionId().
+ if (AV_SYNC_HEADER_V1_SIZE % frameSize != 0) {
+ audioTrack = null;
+ String errorMessage =
+ String.format(
+ "Enable tunnel mode when frame size is unaligned, "
+ + "sampleType: %d, channel: %d, sync header size: %d.",
+ sampleType, channelCount, AV_SYNC_HEADER_V1_SIZE);
+ Log.e(TAG, errorMessage);
+ throw new RuntimeException(errorMessage);
+ }
+ }
+ attributes =
+ new AudioAttributes.Builder()
+ .setContentType(AudioAttributes.CONTENT_TYPE_MOVIE)
+ .setFlags(AudioAttributes.FLAG_HW_AV_SYNC)
+ .setUsage(AudioAttributes.USAGE_MEDIA)
+ .build();
+ } else {
+ // TODO: Investigate if we can use |CONTENT_TYPE_MOVIE| for AudioTrack
+ // used by video playback.
+ attributes =
+ new AudioAttributes.Builder()
+ .setContentType(AudioAttributes.CONTENT_TYPE_MUSIC)
+ .setUsage(AudioAttributes.USAGE_MEDIA)
+ .build();
+ }
AudioFormat format =
new AudioFormat.Builder()
.setEncoding(sampleType)
@@ -66,6 +122,10 @@
.build();
int audioTrackBufferSize = preferredBufferSizeInBytes;
+ // TODO: Investigate if this implementation could be refined.
+ // It is not necessary to loop until 0 since there is new implementation based on
+ // AudioTrack.getMinBufferSize(). Especially for tunnel mode, it would fail if audio HAL does
+ // not support tunnel mode and then it is not helpful to retry.
while (audioTrackBufferSize > 0) {
try {
audioTrack =
@@ -74,7 +134,9 @@
format,
audioTrackBufferSize,
AudioTrack.MODE_STREAM,
- AudioManager.AUDIO_SESSION_ID_GENERATE);
+ tunnelModeEnabled
+ ? tunnelModeAudioSessionId
+ : AudioManager.AUDIO_SESSION_ID_GENERATE);
} catch (Exception e) {
audioTrack = null;
}
@@ -104,6 +166,8 @@
audioTrack.release();
}
audioTrack = null;
+ avSyncHeader = null;
+ avSyncPacketBytesRemaining = 0;
}
@SuppressWarnings("unused")
@@ -144,15 +208,22 @@
return;
}
audioTrack.flush();
+ avSyncHeader = null;
+ avSyncPacketBytesRemaining = 0;
}
@SuppressWarnings("unused")
@UsedByNative
- private int write(byte[] audioData, int sizeInBytes) {
+ private int write(byte[] audioData, int sizeInBytes, long presentationTimeInMicroseconds) {
if (audioTrack == null) {
Log.e(TAG, "Unable to write with NULL audio track.");
return 0;
}
+
+ if (tunnelModeEnabled) {
+ return writeWithAvSync(audioData, sizeInBytes, presentationTimeInMicroseconds);
+ }
+
if (Build.VERSION.SDK_INT >= 23) {
return audioTrack.write(audioData, 0, sizeInBytes, AudioTrack.WRITE_NON_BLOCKING);
} else {
@@ -161,6 +232,66 @@
}
}
+ private int writeWithAvSync(
+ byte[] audioData, int sizeInBytes, long presentationTimeInMicroseconds) {
+ if (audioTrack == null) {
+ throw new RuntimeException("writeWithAvSync() is called when audioTrack is null.");
+ }
+
+ if (!tunnelModeEnabled) {
+ throw new RuntimeException("writeWithAvSync() is called when tunnelModeEnabled is false.");
+ }
+
+ long presentationTimeInNanoseconds = presentationTimeInMicroseconds * 1000;
+
+ // Android support tunnel mode from 5.0 (API level 21), but the app has to manually write the
+ // sync header before API 23, where the write() function with presentation timestamp is
+ // introduced.
+ // Set the following constant to |false| to test manual sync header writing in API level 23 or
+ // later. Note that the code to write sync header manually only supports v1 sync header.
+ final boolean useAutoSyncHeaderWrite = false;
+ if (useAutoSyncHeaderWrite && Build.VERSION.SDK_INT >= 23) {
+ ByteBuffer byteBuffer = ByteBuffer.wrap(audioData);
+ return audioTrack.write(
+ byteBuffer, sizeInBytes, AudioTrack.WRITE_NON_BLOCKING, presentationTimeInNanoseconds);
+ }
+
+ if (avSyncHeader == null) {
+ avSyncHeader = ByteBuffer.allocate(AV_SYNC_HEADER_V1_SIZE);
+ avSyncHeader.order(ByteOrder.BIG_ENDIAN);
+ avSyncHeader.putInt(0x55550001);
+ }
+
+ if (avSyncPacketBytesRemaining == 0) {
+ avSyncHeader.putInt(4, sizeInBytes);
+ avSyncHeader.putLong(8, presentationTimeInNanoseconds);
+ avSyncHeader.position(0);
+ avSyncPacketBytesRemaining = sizeInBytes;
+ }
+
+ if (avSyncHeader.remaining() > 0) {
+ int ret =
+ audioTrack.write(avSyncHeader, avSyncHeader.remaining(), AudioTrack.WRITE_NON_BLOCKING);
+ if (ret < 0) {
+ avSyncPacketBytesRemaining = 0;
+ return ret;
+ }
+ if (avSyncHeader.remaining() > 0) {
+ return 0;
+ }
+ }
+
+ int sizeToWrite = Math.min(avSyncPacketBytesRemaining, sizeInBytes);
+ ByteBuffer byteBuffer = ByteBuffer.wrap(audioData);
+ int ret = audioTrack.write(byteBuffer, sizeToWrite, AudioTrack.WRITE_NON_BLOCKING);
+ if (ret < 0) {
+ avSyncPacketBytesRemaining = 0;
+ return ret;
+ }
+ avSyncPacketBytesRemaining -= ret;
+ return ret;
+ }
+
@SuppressWarnings("unused")
@UsedByNative
private int write(float[] audioData, int sizeInFloats) {
@@ -168,6 +299,9 @@
Log.e(TAG, "Unable to write with NULL audio track.");
return 0;
}
+ if (tunnelModeEnabled) {
+ throw new RuntimeException("Float sample is not supported under tunnel mode.");
+ }
return audioTrack.write(audioData, 0, sizeInFloats, AudioTrack.WRITE_NON_BLOCKING);
}
diff --git a/src/starboard/android/apk/app/src/main/java/dev/cobalt/media/MediaCodecUtil.java b/src/starboard/android/apk/app/src/main/java/dev/cobalt/media/MediaCodecUtil.java
index 71e6857..03fb7cc 100644
--- a/src/starboard/android/apk/app/src/main/java/dev/cobalt/media/MediaCodecUtil.java
+++ b/src/starboard/android/apk/app/src/main/java/dev/cobalt/media/MediaCodecUtil.java
@@ -682,52 +682,69 @@
* Debug utility function that can be locally added to dump information about all decoders on a
* particular system.
*/
- @SuppressWarnings("unused")
- private static void dumpAllDecoders() {
+ public static void dumpAllDecoders() {
+ String decoderDumpString = "";
for (MediaCodecInfo info : new MediaCodecList(MediaCodecList.ALL_CODECS).getCodecInfos()) {
if (info.isEncoder()) {
continue;
}
for (String supportedType : info.getSupportedTypes()) {
String name = info.getName();
- CodecCapabilities codecCapabilities = info.getCapabilitiesForType(supportedType);
- Log.v(TAG, "==================================================");
- Log.v(TAG, String.format("name: %s", name));
- Log.v(TAG, String.format("supportedType: %s", supportedType));
- Log.v(
- TAG, String.format("codecBlackList.contains(name): %b", codecBlackList.contains(name)));
- Log.v(
- TAG,
+ decoderDumpString +=
String.format(
- "FEATURE_SecurePlayback: %b",
- codecCapabilities.isFeatureSupported(
- MediaCodecInfo.CodecCapabilities.FEATURE_SecurePlayback)));
+ "name: %s (%s, %s):",
+ name,
+ supportedType,
+ codecBlackList.contains(name) ? "blacklisted" : "not blacklisted");
+ CodecCapabilities codecCapabilities = info.getCapabilitiesForType(supportedType);
VideoCapabilities videoCapabilities = codecCapabilities.getVideoCapabilities();
if (videoCapabilities != null) {
- Log.v(
- TAG,
+ decoderDumpString +=
String.format(
- "videoCapabilities.getSupportedWidths(): %s",
- videoCapabilities.getSupportedWidths().toString()));
- Log.v(
- TAG,
- String.format(
- "videoCapabilities.getSupportedHeights(): %s",
- videoCapabilities.getSupportedHeights().toString()));
- Log.v(
- TAG,
- String.format(
- "videoCapabilities.getBitrateRange(): %s",
- videoCapabilities.getBitrateRange().toString()));
- Log.v(
- TAG,
- String.format(
- "videoCapabilities.getSupportedFrameRates(): %s",
- videoCapabilities.getSupportedFrameRates().toString()));
+ "\n\t\t"
+ + "widths: %s, "
+ + "heights: %s, "
+ + "bitrates: %s, "
+ + "framerates: %s, ",
+ videoCapabilities.getSupportedWidths().toString(),
+ videoCapabilities.getSupportedHeights().toString(),
+ videoCapabilities.getBitrateRange().toString(),
+ videoCapabilities.getSupportedFrameRates().toString());
}
- Log.v(TAG, "==================================================");
- Log.v(TAG, "");
+ boolean adaptivePlayback =
+ codecCapabilities.isFeatureSupported(
+ MediaCodecInfo.CodecCapabilities.FEATURE_AdaptivePlayback);
+ boolean securePlayback =
+ codecCapabilities.isFeatureSupported(
+ MediaCodecInfo.CodecCapabilities.FEATURE_SecurePlayback);
+ boolean tunneledPlayback =
+ codecCapabilities.isFeatureSupported(
+ MediaCodecInfo.CodecCapabilities.FEATURE_TunneledPlayback);
+ if (adaptivePlayback || securePlayback || tunneledPlayback) {
+ decoderDumpString +=
+ String.format(
+ "(%s%s%s",
+ adaptivePlayback ? "AdaptivePlayback, " : "",
+ securePlayback ? "SecurePlayback, " : "",
+ tunneledPlayback ? "TunneledPlayback, " : "");
+ // Remove trailing space and comma
+ decoderDumpString = decoderDumpString.substring(0, decoderDumpString.length() - 2);
+ decoderDumpString += ")";
+ } else {
+ decoderDumpString += " No extra features supported";
+ }
+ decoderDumpString += "\n";
}
}
+ Log.v(
+ TAG,
+ String.format(
+ " \n"
+ + "==================================================\n"
+ + "Full list of decoder features: [AdaptivePlayback, SecurePlayback,"
+ + " TunneledPlayback]\n"
+ + "Unsupported features for each codec are not listed\n"
+ + decoderDumpString
+ + "=================================================="));
}
}
diff --git a/src/starboard/android/apk/build.id b/src/starboard/android/apk/build.id
new file mode 100644
index 0000000..d3b971d
--- /dev/null
+++ b/src/starboard/android/apk/build.id
@@ -0,0 +1 @@
+289402
\ No newline at end of file
diff --git a/src/starboard/android/shared/audio_sink_min_required_frames_tester.cc b/src/starboard/android/shared/audio_sink_min_required_frames_tester.cc
index a5a77a7..88f3762 100644
--- a/src/starboard/android/shared/audio_sink_min_required_frames_tester.cc
+++ b/src/starboard/android/shared/audio_sink_min_required_frames_tester.cc
@@ -123,7 +123,8 @@
min_required_frames_ * task.number_of_channels *
GetSampleSize(task.sample_type),
&MinRequiredFramesTester::UpdateSourceStatusFunc,
- &MinRequiredFramesTester::ConsumeFramesFunc, this);
+ &MinRequiredFramesTester::ConsumeFramesFunc,
+ &MinRequiredFramesTester::ErrorFunc, 0, -1, this);
{
ScopedLock scoped_lock(mutex_);
wait_timeout = !condition_variable_.WaitTimed(kSbTimeSecond * 5);
@@ -174,6 +175,14 @@
tester->ConsumeFrames(frames_consumed);
}
+// static
+void MinRequiredFramesTester::ErrorFunc(bool capability_changed,
+ void* context) {
+ // TODO: Handle errors during minimum frames test, maybe by terminating the
+ // test earlier.
+ SB_NOTREACHED();
+}
+
void MinRequiredFramesTester::UpdateSourceStatus(int* frames_in_buffer,
int* offset_in_frames,
bool* is_playing,
diff --git a/src/starboard/android/shared/audio_sink_min_required_frames_tester.h b/src/starboard/android/shared/audio_sink_min_required_frames_tester.h
index 290011d..e689e96 100644
--- a/src/starboard/android/shared/audio_sink_min_required_frames_tester.h
+++ b/src/starboard/android/shared/audio_sink_min_required_frames_tester.h
@@ -85,6 +85,7 @@
static void ConsumeFramesFunc(int frames_consumed,
SbTime frames_consumed_at,
void* context);
+ static void ErrorFunc(bool capability_changed, void* context);
void UpdateSourceStatus(int* frames_in_buffer,
int* offset_in_frames,
bool* is_playing,
diff --git a/src/starboard/android/shared/audio_track_audio_sink_type.cc b/src/starboard/android/shared/audio_track_audio_sink_type.cc
index 44dffc8..cf9d744 100644
--- a/src/starboard/android/shared/audio_track_audio_sink_type.cc
+++ b/src/starboard/android/shared/audio_track_audio_sink_type.cc
@@ -29,11 +29,23 @@
namespace shared {
namespace {
+// The same as AudioTrack.ERROR_DEAD_OBJECT.
+const int kAudioTrackErrorDeadObject = -6;
+
// The maximum number of frames that can be written to android audio track per
// write request. If we don't set this cap for writing frames to audio track,
// we will repeatedly allocate a large byte array which cannot be consumed by
// audio track completely.
const int kMaxFramesPerRequest = 65536;
+
+// Most Android audio HAL updates audio time for A/V synchronization on audio
+// sync frames. For example, audio HAL may try to render when it gets an entire
+// sync frame and then update audio time. Shorter duration of sync frame
+// improves the accuracy of audio time, especially at the beginning of a
+// playback, as otherwise the audio time during the initial update may be too
+// large (non zero) and results in dropped video frames.
+const SbTime kMaxDurationPerRequestInTunnelMode = 16 * kSbTimeMillisecond;
+
const jint kNoOffset = 0;
const size_t kSilenceFramesPerAppend = 1024;
@@ -74,6 +86,12 @@
return static_cast<uint8_t*>(pointer) + offset;
}
+int GetMaxFramesPerRequestForTunnelMode(int sampling_frequency_hz) {
+ auto max_frames = kMaxDurationPerRequestInTunnelMode * sampling_frequency_hz /
+ kSbTimeSecond;
+ return (max_frames + 15) / 16 * 16; // align to 16
+}
+
} // namespace
AudioTrackAudioSink::AudioTrackAudioSink(
@@ -86,6 +104,9 @@
int preferred_buffer_size_in_bytes,
SbAudioSinkUpdateSourceStatusFunc update_source_status_func,
ConsumeFramesFunc consume_frames_func,
+ SbAudioSinkPrivate::ErrorFunc error_func,
+ SbTime start_time,
+ int tunnel_mode_audio_session_id,
void* context)
: type_(type),
channels_(channels),
@@ -95,40 +116,56 @@
frames_per_channel_(frames_per_channel),
update_source_status_func_(update_source_status_func),
consume_frames_func_(consume_frames_func),
- context_(context),
- last_playback_head_position_(0),
- j_audio_track_bridge_(NULL),
- j_audio_data_(NULL),
- quit_(false),
- audio_out_thread_(kSbThreadInvalid),
- playback_rate_(1.0f),
- written_frames_(0) {
+ error_func_(error_func),
+ start_time_(start_time),
+ tunnel_mode_audio_session_id_(tunnel_mode_audio_session_id),
+ max_frames_per_request_(
+ tunnel_mode_audio_session_id_ == -1
+ ? kMaxFramesPerRequest
+ : GetMaxFramesPerRequestForTunnelMode(sampling_frequency_hz_)),
+ context_(context) {
SB_DCHECK(update_source_status_func_);
SB_DCHECK(consume_frames_func_);
SB_DCHECK(frame_buffer_);
SB_DCHECK(SbAudioSinkIsAudioSampleTypeSupported(sample_type));
+ // TODO: Support query if platform supports float type for tunnel mode.
+ if (tunnel_mode_audio_session_id_ != -1) {
+ SB_DCHECK(sample_type_ == kSbMediaAudioSampleTypeInt16Deprecated);
+ }
+
+ SB_LOG(INFO) << "Creating audio sink starts at " << start_time_;
+
JniEnvExt* env = JniEnvExt::Get();
ScopedLocalJavaRef<jobject> j_audio_output_manager(
env->CallStarboardObjectMethodOrAbort(
"getAudioOutputManager", "()Ldev/cobalt/media/AudioOutputManager;"));
jobject j_audio_track_bridge = env->CallObjectMethodOrAbort(
j_audio_output_manager.Get(), "createAudioTrackBridge",
- "(IIII)Ldev/cobalt/media/AudioTrackBridge;",
+ "(IIIII)Ldev/cobalt/media/AudioTrackBridge;",
GetAudioFormatSampleType(sample_type_), sampling_frequency_hz_, channels_,
- preferred_buffer_size_in_bytes);
+ preferred_buffer_size_in_bytes, tunnel_mode_audio_session_id_);
if (!j_audio_track_bridge) {
+ // One of the cases that this may hit is when output happened to be switched
+ // to a device that doesn't support tunnel mode.
+ // TODO: Find a way to exclude the device from tunnel mode playback, to
+ // avoid infinite loop in creating the audio sink on a device
+ // claims to support tunnel mode but fails to create the audio sink.
+ // TODO: Currently this will be reported as a general decode error,
+ // investigate if this can be reported as a capability changed error.
return;
}
j_audio_track_bridge_ = env->ConvertLocalRefToGlobalRef(j_audio_track_bridge);
if (sample_type_ == kSbMediaAudioSampleTypeFloat32) {
- j_audio_data_ = env->NewFloatArray(channels_ * kMaxFramesPerRequest);
+ j_audio_data_ = env->NewFloatArray(channels_ * max_frames_per_request_);
} else if (sample_type_ == kSbMediaAudioSampleTypeInt16Deprecated) {
j_audio_data_ = env->NewByteArray(channels_ * GetSampleSize(sample_type_) *
- kMaxFramesPerRequest);
+ max_frames_per_request_);
} else {
SB_NOTREACHED();
}
+ SB_CHECK(j_audio_data_) << "Failed to allocate |j_audio_data_|";
+
j_audio_data_ = env->ConvertLocalRefToGlobalRef(j_audio_data_);
audio_out_thread_ = SbThreadCreate(
@@ -183,15 +220,21 @@
return NULL;
}
+// TODO: Break down the function into manageable pieces.
void AudioTrackAudioSink::AudioThreadFunc() {
JniEnvExt* env = JniEnvExt::Get();
bool was_playing = false;
SB_LOG(INFO) << "AudioTrackAudioSink thread started.";
-#if defined(SB_PLAYER_FILTER_ENABLE_STATE_CHECK)
+ int accumulated_written_frames = 0;
+ // TODO: |last_playback_head_changed_at| is also resetted when a warning is
+ // logged after the playback head position hasn't been updated for a
+ // while. We should refine the name to make it better reflect its
+ // usage.
SbTime last_playback_head_changed_at = -1;
-#endif // defined(SB_PLAYER_FILTER_ENABLE_STATE_CHECK)
+ SbTime playback_head_not_changed_duration = 0;
+ SbTime last_written_succeeded_at = -1;
while (!quit_) {
int playback_head_position = 0;
@@ -214,12 +257,15 @@
std::max(playback_head_position, last_playback_head_position_);
int frames_consumed =
playback_head_position - last_playback_head_position_;
+ SbTime now = SbTimeGetMonotonicNow();
-#if defined(SB_PLAYER_FILTER_ENABLE_STATE_CHECK)
+ if (last_playback_head_changed_at == -1) {
+ last_playback_head_changed_at = now;
+ }
if (last_playback_head_position_ == playback_head_position) {
- auto now = SbTimeGetMonotonicNow();
SbTime elapsed = now - last_playback_head_changed_at;
- if (was_playing && elapsed > 5 * kSbTimeSecond) {
+ if (elapsed > 5 * kSbTimeSecond) {
+ playback_head_not_changed_duration += elapsed;
last_playback_head_changed_at = now;
SB_LOG(INFO) << "last playback head position is "
<< last_playback_head_position_
@@ -227,9 +273,9 @@
<< " microseconds.";
}
} else {
- last_playback_head_changed_at = SbTimeGetMonotonicNow();
+ last_playback_head_changed_at = now;
+ playback_head_not_changed_duration = 0;
}
-#endif // defined(SB_PLAYER_FILTER_ENABLE_STATE_CHECK)
last_playback_head_position_ = playback_head_position;
frames_consumed = std::min(frames_consumed, written_frames_);
@@ -260,6 +306,9 @@
SB_LOG(INFO) << "AudioTrackAudioSink paused.";
} else if (!was_playing && is_playing) {
was_playing = true;
+ last_playback_head_changed_at = -1;
+ playback_head_not_changed_duration = 0;
+ last_written_succeeded_at = -1;
env->CallVoidMethodOrAbort(j_audio_track_bridge_, "play", "()V");
SB_LOG(INFO) << "AudioTrackAudioSink playing.";
}
@@ -281,7 +330,7 @@
}
expected_written_frames =
- std::min(expected_written_frames, kMaxFramesPerRequest);
+ std::min(expected_written_frames, max_frames_per_request_);
if (expected_written_frames == 0) {
// It is possible that all the frames in buffer are written to the
// soundcard, but those are not being consumed. If eos is reached,
@@ -292,24 +341,84 @@
// Currently AudioDevice and AudioRenderer will write tail silence.
// It should be reached only in tests. It's not ideal to allocate
// a new silence buffer every time.
- std::vector<uint8_t> silence_buffer(
- channels_ * GetSampleSize(sample_type_) * kSilenceFramesPerAppend);
- WriteData(env, silence_buffer.data(), kSilenceFramesPerAppend);
+ const int silence_frames_per_append =
+ std::min<int>(kSilenceFramesPerAppend, max_frames_per_request_);
+ std::vector<uint8_t> silence_buffer(channels_ *
+ GetSampleSize(sample_type_) *
+ silence_frames_per_append);
+ auto sync_time = start_time_ + accumulated_written_frames *
+ kSbTimeSecond /
+ sampling_frequency_hz_;
+ // Not necessary to handle error of WriteData(), even for
+ // kAudioTrackErrorDeadObject, as the audio has reached the end of
+ // stream.
+ // TODO: Ensure that the audio stream can still reach the end when an
+ // error occurs.
+ WriteData(env, silence_buffer.data(), silence_frames_per_append,
+ sync_time);
}
+
+ // While WriteData() returns kAudioTrackErrorDeadObject on dead object,
+ // getAudioTimestamp() doesn't, it just no longer updates its return
+ // value. If the dead object error occurs when there isn't any audio data
+ // to write, there is no way to detect it by checking the return value of
+ // getAudioTimestamp(). Instead, we have to check if its return value has
+ // been changed during a certain period of time, to detect the underlying
+ // dead object error.
+ // Note that dead object would occur while switching audio end points in
+ // tunnel mode. Under non-tunnel mode, the Android native AudioTrack will
+ // handle audio track dead object automatically if the new end point can
+ // support current audio format.
+ // TODO: Investigate to handle this error in non-tunnel mode.
+ if (tunnel_mode_audio_session_id_ != -1 &&
+ last_written_succeeded_at != -1) {
+ const SbTime kAudioSinkBlockedDuration = kSbTimeSecond;
+ auto time_since_last_written_success =
+ SbTimeGetMonotonicNow() - last_written_succeeded_at;
+ if (time_since_last_written_success > kAudioSinkBlockedDuration &&
+ playback_head_not_changed_duration > kAudioSinkBlockedDuration &&
+ tunnel_mode_audio_session_id_ != -1) {
+ SB_LOG(INFO) << "Over one second without frames written and consumed";
+ consume_frames_func_(written_frames_, SbTimeGetMonotonicNow(),
+ context_);
+ error_func_(kSbPlayerErrorCapabilityChanged, context_);
+ break;
+ }
+ }
+
SbThreadSleep(10 * kSbTimeMillisecond);
continue;
}
SB_DCHECK(expected_written_frames > 0);
+ auto sync_time = start_time_ + accumulated_written_frames * kSbTimeSecond /
+ sampling_frequency_hz_;
+
+ SB_CHECK(start_position + expected_written_frames <= frames_per_channel_);
int written_frames = WriteData(
env,
IncrementPointerByBytes(frame_buffer_, start_position * channels_ *
GetSampleSize(sample_type_)),
- expected_written_frames);
+ expected_written_frames, sync_time);
+ SbTime now = SbTimeGetMonotonicNow();
+
+ if (written_frames < 0) {
+ // Take all |written_frames_| as consumed since audio track could be dead.
+ consume_frames_func_(written_frames_, now, context_);
+ error_func_(written_frames == kAudioTrackErrorDeadObject
+ ? kSbPlayerErrorCapabilityChanged
+ : kSbPlayerErrorDecode,
+ context_);
+ break;
+ } else if (written_frames > 0) {
+ last_written_succeeded_at = now;
+ }
written_frames_ += written_frames;
+ accumulated_written_frames += written_frames;
+
bool written_fully = (written_frames == expected_written_frames);
auto unplayed_frames_in_time =
written_frames_ * kSbTimeSecond / sampling_frequency_hz_ -
- (SbTimeGetMonotonicNow() - frames_consumed_at);
+ (now - frames_consumed_at);
// As long as there is enough data in the buffer, run the loop in lower
// frequency to avoid taking too much CPU. Note that the threshold should
// be big enough to account for the unstable playback head reported at the
@@ -332,8 +441,9 @@
}
int AudioTrackAudioSink::WriteData(JniEnvExt* env,
- const void* buffer,
- int expected_written_frames) {
+ void* buffer,
+ int expected_written_frames,
+ SbTime sync_time) {
if (sample_type_ == kSbMediaAudioSampleTypeFloat32) {
int expected_written_size = expected_written_frames * channels_;
env->SetFloatArrayRegion(static_cast<jfloatArray>(j_audio_data_), kNoOffset,
@@ -342,7 +452,10 @@
int written =
env->CallIntMethodOrAbort(j_audio_track_bridge_, "write", "([FI)I",
j_audio_data_, expected_written_size);
- SB_DCHECK(written >= 0);
+ if (written < 0) {
+ // Error code returned as negative value, like kAudioTrackErrorDeadObject.
+ return written;
+ }
SB_DCHECK(written % channels_ == 0);
return written / channels_;
}
@@ -352,10 +465,14 @@
env->SetByteArrayRegion(static_cast<jbyteArray>(j_audio_data_), kNoOffset,
expected_written_size,
static_cast<const jbyte*>(buffer));
- int written =
- env->CallIntMethodOrAbort(j_audio_track_bridge_, "write", "([BI)I",
- j_audio_data_, expected_written_size);
- SB_DCHECK(written >= 0);
+
+ int written = env->CallIntMethodOrAbort(j_audio_track_bridge_, "write",
+ "([BIJ)I", j_audio_data_,
+ expected_written_size, sync_time);
+ if (written < 0) {
+ // Error code returned as negative value, like kAudioTrackErrorDeadObject.
+ return written;
+ }
SB_DCHECK(written % (channels_ * GetSampleSize(sample_type_)) == 0);
return written / (channels_ * GetSampleSize(sample_type_));
}
@@ -417,6 +534,27 @@
SbAudioSinkPrivate::ConsumeFramesFunc consume_frames_func,
SbAudioSinkPrivate::ErrorFunc error_func,
void* context) {
+ const SbTime kStartTime = 0;
+ const int kTunnelModeAudioSessionId = -1; // disable tunnel mode
+ return Create(channels, sampling_frequency_hz, audio_sample_type,
+ audio_frame_storage_type, frame_buffers, frames_per_channel,
+ update_source_status_func, consume_frames_func, error_func,
+ kStartTime, kTunnelModeAudioSessionId, context);
+}
+
+SbAudioSink AudioTrackAudioSinkType::Create(
+ int channels,
+ int sampling_frequency_hz,
+ SbMediaAudioSampleType audio_sample_type,
+ SbMediaAudioFrameStorageType audio_frame_storage_type,
+ SbAudioSinkFrameBuffers frame_buffers,
+ int frames_per_channel,
+ SbAudioSinkUpdateSourceStatusFunc update_source_status_func,
+ SbAudioSinkPrivate::ConsumeFramesFunc consume_frames_func,
+ SbAudioSinkPrivate::ErrorFunc error_func,
+ SbTime start_media_time,
+ int tunnel_mode_audio_session_id,
+ void* context) {
int min_required_frames = SbAudioSinkGetMinBufferSizeInFrames(
channels, audio_sample_type, sampling_frequency_hz);
SB_DCHECK(frames_per_channel >= min_required_frames);
@@ -425,7 +563,8 @@
AudioTrackAudioSink* audio_sink = new AudioTrackAudioSink(
this, channels, sampling_frequency_hz, audio_sample_type, frame_buffers,
frames_per_channel, preferred_buffer_size_in_bytes,
- update_source_status_func, consume_frames_func, context);
+ update_source_status_func, consume_frames_func, error_func,
+ start_media_time, tunnel_mode_audio_session_id, context);
if (!audio_sink->IsAudioTrackValid()) {
SB_DLOG(ERROR)
<< "AudioTrackAudioSinkType::Create failed to create audio track";
diff --git a/src/starboard/android/shared/audio_track_audio_sink_type.h b/src/starboard/android/shared/audio_track_audio_sink_type.h
index 43b0c86..c5b1ba7 100644
--- a/src/starboard/android/shared/audio_track_audio_sink_type.h
+++ b/src/starboard/android/shared/audio_track_audio_sink_type.h
@@ -18,6 +18,7 @@
#include <atomic>
#include <functional>
#include <map>
+#include <vector>
#include "starboard/android/shared/audio_sink_min_required_frames_tester.h"
#include "starboard/android/shared/jni_env_ext.h"
@@ -54,6 +55,19 @@
SbAudioSinkPrivate::ConsumeFramesFunc consume_frames_func,
SbAudioSinkPrivate::ErrorFunc error_func,
void* context) override;
+ SbAudioSink Create(
+ int channels,
+ int sampling_frequency_hz,
+ SbMediaAudioSampleType audio_sample_type,
+ SbMediaAudioFrameStorageType audio_frame_storage_type,
+ SbAudioSinkFrameBuffers frame_buffers,
+ int frames_per_channel,
+ SbAudioSinkUpdateSourceStatusFunc update_source_status_func,
+ SbAudioSinkPrivate::ConsumeFramesFunc consume_frames_func,
+ SbAudioSinkPrivate::ErrorFunc error_func,
+ SbTime start_time,
+ int tunnel_mode_audio_session_id,
+ void* context);
bool IsValid(SbAudioSink audio_sink) override {
return audio_sink != kSbAudioSinkInvalid && audio_sink->IsType(this);
@@ -92,6 +106,9 @@
int preferred_buffer_size,
SbAudioSinkUpdateSourceStatusFunc update_source_status_func,
ConsumeFramesFunc consume_frames_func,
+ SbAudioSinkPrivate::ErrorFunc error_func,
+ SbTime start_media_time,
+ int tunnel_mode_audio_session_id,
void* context);
~AudioTrackAudioSink() override;
@@ -106,8 +123,9 @@
static void* ThreadEntryPoint(void* context);
void AudioThreadFunc();
- int WriteData(JniEnvExt* env, const void* buffer, int size);
+ int WriteData(JniEnvExt* env, void* buffer, int size, SbTime sync_time);
+ // TODO: Add const to the following variables where appropriate.
Type* type_;
int channels_;
int sampling_frequency_hz_;
@@ -116,18 +134,25 @@
int frames_per_channel_;
SbAudioSinkUpdateSourceStatusFunc update_source_status_func_;
ConsumeFramesFunc consume_frames_func_;
+ SbAudioSinkPrivate::ErrorFunc error_func_;
+ const SbTime start_time_;
+ const int tunnel_mode_audio_session_id_;
+ const int max_frames_per_request_;
+
void* context_;
- int last_playback_head_position_;
- jobject j_audio_track_bridge_;
- jobject j_audio_data_;
+ int last_playback_head_position_ = 0;
+ jobject j_audio_track_bridge_ = nullptr;
+ jobject j_audio_data_ = nullptr;
- volatile bool quit_;
- SbThread audio_out_thread_;
+ volatile bool quit_ = false;
+ SbThread audio_out_thread_ = kSbThreadInvalid;
- starboard::Mutex mutex_;
- double playback_rate_;
+ Mutex mutex_;
+ double playback_rate_ = 1.0;
- int written_frames_;
+ // TODO: Rename to |frames_in_audio_track| and move it into AudioThreadFunc()
+ // as a local variable.
+ int written_frames_ = 0;
};
} // namespace shared
diff --git a/src/starboard/android/shared/configuration_constants.cc b/src/starboard/android/shared/configuration_constants.cc
index bbf77e7..a7a09fd 100644
--- a/src/starboard/android/shared/configuration_constants.cc
+++ b/src/starboard/android/shared/configuration_constants.cc
@@ -83,19 +83,6 @@
// video.
const uint32_t kSbMediaMaxVideoBitrateInBitsPerSecond = 200 * 1024 * 1024;
-// Specify the number of video frames to be cached during playback. A large
-// value leads to more stable fps but also causes the app to use more memory.
-const uint32_t kSbMediaMaximumVideoFrames = 12;
-
-// The encoded video frames are compressed in different ways, their decoding
-// time can vary a lot. Occasionally a single frame can take longer time to
-// decode than the average time per frame. The player has to cache some frames
-// to account for such inconsistency. The number of frames being cached are
-// controlled by the following two macros.
-//
-// Specify the number of video frames to be cached before the playback starts.
-// Note that set this value too large may increase the playback start delay.
-const uint32_t kSbMediaMaximumVideoPrerollFrames = 4;
// Specifies how video frame buffers must be aligned on this platform.
const uint32_t kSbMediaVideoFrameAlignment = 256;
diff --git a/src/starboard/android/shared/configuration_public.h b/src/starboard/android/shared/configuration_public.h
index e428200..30374c7 100644
--- a/src/starboard/android/shared/configuration_public.h
+++ b/src/starboard/android/shared/configuration_public.h
@@ -31,10 +31,6 @@
// --- Architecture Configuration --------------------------------------------
-// Indicates that there is no support for alignment at greater than 16 bytes for
-// items on the stack.
-#define SB_HAS_QUIRK_DOES_NOT_STACK_ALIGN_OVER_16_BYTES 1
-
// --- System Header Configuration -------------------------------------------
// Any system headers listed here that are not provided by the platform will be
@@ -163,13 +159,21 @@
// --- User Configuration ----------------------------------------------------
+// --- Platform Specific Configuration ---------------------------------------
+
+// Enable SB_HAS_CONCEALED_STATE support.
+#define SB_HAS_CONCEALED_STATE 1
+
// --- Platform Specific Audits ----------------------------------------------
#if !defined(__GNUC__)
#error "Android builds need a GCC-like compiler (for the moment)."
#endif
-// Enable SB_HAS_CONCEALED_STATE support.
-#define SB_HAS_CONCEALED_STATE 1
+// --- Platform Specific Quirks ----------------------------------------------
+
+// Indicates that there is no support for alignment at greater than 16 bytes for
+// items on the stack.
+#define SB_HAS_QUIRK_DOES_NOT_STACK_ALIGN_OVER_16_BYTES 1
#endif // STARBOARD_ANDROID_SHARED_CONFIGURATION_PUBLIC_H_
diff --git a/src/starboard/android/shared/gyp_configuration.py b/src/starboard/android/shared/gyp_configuration.py
index 3474905..7aecf6e 100644
--- a/src/starboard/android/shared/gyp_configuration.py
+++ b/src/starboard/android/shared/gyp_configuration.py
@@ -305,10 +305,7 @@
'SbFileGetPathInfoTest.WorksOnStaticContentDirectories',
# Android doesn't currently support specifying a bitrate under 8000
'SbMediaCanPlayMimeAndKeySystem.MinimumSupport',
- # There are issues with playback of heeac format files where the input
- # |frames_per_channel| is 6912, instead of 12544 (as with other
- # formats).
- 'SbPlayerWriteSampleTests/SbPlayerWriteSampleTest.NoInput/6',
+
# These tests are disabled due to not receiving the kEndOfStream
# player state update within the specified timeout.
'SbPlayerWriteSampleTests/SbPlayerWriteSampleTest.NoInput/7',
diff --git a/src/starboard/android/shared/jni_utils.h b/src/starboard/android/shared/jni_utils.h
index 811a309..2dae0c1 100644
--- a/src/starboard/android/shared/jni_utils.h
+++ b/src/starboard/android/shared/jni_utils.h
@@ -53,7 +53,8 @@
private:
JT jt_;
- SB_DISALLOW_COPY_AND_ASSIGN(ScopedLocalJavaRef);
+ ScopedLocalJavaRef(const ScopedLocalJavaRef&) = delete;
+ void operator=(const ScopedLocalJavaRef&) = delete;
};
// Convenience class to manage the lifetime of a local Java ByteBuffer
@@ -78,7 +79,8 @@
private:
ScopedLocalJavaRef<jobject> j_byte_buffer_;
- SB_DISALLOW_COPY_AND_ASSIGN(ScopedJavaByteBuffer);
+ ScopedJavaByteBuffer(const ScopedJavaByteBuffer&) = delete;
+ void operator=(const ScopedJavaByteBuffer&) = delete;
};
} // namespace shared
diff --git a/src/starboard/android/shared/launcher.py b/src/starboard/android/shared/launcher.py
index 566e595..106b2b9 100644
--- a/src/starboard/android/shared/launcher.py
+++ b/src/starboard/android/shared/launcher.py
@@ -117,6 +117,8 @@
line = CleanLine(self.process.stdout.readline())
if not line:
return
+ # Show the crash lines reported by "am monitor".
+ sys.stderr.write(line)
if re.search(_RE_ADB_AM_MONITOR_ERROR, line):
self.done_queue.put(_QUEUE_CODE_CRASHED)
# This log line will wake up the main thread
@@ -311,6 +313,7 @@
'raw',
'-s',
'*:F',
+ '*:E',
'DEBUG:*',
'System.err:*',
'starboard:*',
diff --git a/src/starboard/android/shared/media_codec_bridge.h b/src/starboard/android/shared/media_codec_bridge.h
index 77452c1..e68c69a 100644
--- a/src/starboard/android/shared/media_codec_bridge.h
+++ b/src/starboard/android/shared/media_codec_bridge.h
@@ -162,7 +162,8 @@
// |GetOutputDimensions|.
jobject j_reused_get_output_format_result_ = NULL;
- SB_DISALLOW_COPY_AND_ASSIGN(MediaCodecBridge);
+ MediaCodecBridge(const MediaCodecBridge&) = delete;
+ void operator=(const MediaCodecBridge&) = delete;
};
} // namespace shared
diff --git a/src/starboard/android/shared/player_components_factory.cc b/src/starboard/android/shared/player_components_factory.cc
index 6ac984a..01dc7a6 100644
--- a/src/starboard/android/shared/player_components_factory.cc
+++ b/src/starboard/android/shared/player_components_factory.cc
@@ -12,23 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-#include "starboard/android/shared/audio_decoder.h"
-#include "starboard/android/shared/video_decoder.h"
-#include "starboard/android/shared/video_render_algorithm.h"
-#include "starboard/common/log.h"
-#include "starboard/common/ref_counted.h"
-#include "starboard/common/scoped_ptr.h"
-#include "starboard/media.h"
-#include "starboard/shared/opus/opus_audio_decoder.h"
-#include "starboard/shared/starboard/player/filter/adaptive_audio_decoder_internal.h"
-#include "starboard/shared/starboard/player/filter/audio_decoder_internal.h"
-#include "starboard/shared/starboard/player/filter/audio_renderer_sink.h"
-#include "starboard/shared/starboard/player/filter/audio_renderer_sink_impl.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/filter/video_render_algorithm.h"
-#include "starboard/shared/starboard/player/filter/video_render_algorithm_impl.h"
-#include "starboard/shared/starboard/player/filter/video_renderer_sink.h"
+#include "starboard/android/shared/player_components_factory.h"
namespace starboard {
namespace shared {
@@ -36,121 +20,10 @@
namespace player {
namespace filter {
-namespace {
-
-const int kAudioSinkFramesAlignment = 256;
-const int kDefaultAudioSinkMinFramesPerAppend = 1024;
-const int kDefaultAudioSinkMaxCachedFrames =
- 8 * kDefaultAudioSinkMinFramesPerAppend;
-
-int AlignUp(int value, int alignment) {
- return (value + alignment - 1) / alignment * alignment;
-}
-
-class PlayerComponentsFactory : public PlayerComponents::Factory {
- bool CreateSubComponents(
- const CreationParameters& creation_parameters,
- scoped_ptr<AudioDecoder>* audio_decoder,
- scoped_ptr<AudioRendererSink>* audio_renderer_sink,
- scoped_ptr<VideoDecoder>* video_decoder,
- scoped_ptr<VideoRenderAlgorithm>* video_render_algorithm,
- scoped_refptr<VideoRendererSink>* video_renderer_sink,
- std::string* error_message) override {
- SB_DCHECK(error_message);
-
- if (creation_parameters.audio_codec() != kSbMediaAudioCodecNone) {
- SB_DCHECK(audio_decoder);
- SB_DCHECK(audio_renderer_sink);
-
- auto decoder_creator = [](const SbMediaAudioSampleInfo& audio_sample_info,
- SbDrmSystem drm_system) {
- if (audio_sample_info.codec == kSbMediaAudioCodecAac) {
- scoped_ptr<android::shared::AudioDecoder> audio_decoder_impl(
- new android::shared::AudioDecoder(audio_sample_info.codec,
- audio_sample_info, drm_system));
- if (audio_decoder_impl->is_valid()) {
- return audio_decoder_impl.PassAs<AudioDecoder>();
- }
- } else if (audio_sample_info.codec == kSbMediaAudioCodecOpus) {
- scoped_ptr<opus::OpusAudioDecoder> audio_decoder_impl(
- new opus::OpusAudioDecoder(audio_sample_info));
- if (audio_decoder_impl->is_valid()) {
- return audio_decoder_impl.PassAs<AudioDecoder>();
- }
- } else {
- SB_NOTREACHED();
- }
- return scoped_ptr<AudioDecoder>();
- };
-
- audio_decoder->reset(new AdaptiveAudioDecoder(
- creation_parameters.audio_sample_info(),
- creation_parameters.drm_system(), decoder_creator));
- audio_renderer_sink->reset(new AudioRendererSinkImpl);
- }
-
- if (creation_parameters.video_codec() != kSbMediaVideoCodecNone) {
- SB_DCHECK(video_decoder);
- SB_DCHECK(video_render_algorithm);
- SB_DCHECK(video_renderer_sink);
- SB_DCHECK(error_message);
-
- scoped_ptr<android::shared::VideoDecoder> video_decoder_impl(
- new android::shared::VideoDecoder(
- creation_parameters.video_codec(),
- creation_parameters.drm_system(),
- creation_parameters.output_mode(),
- creation_parameters.decode_target_graphics_context_provider(),
- creation_parameters.max_video_capabilities(), error_message));
- if (video_decoder_impl->is_valid()) {
- video_render_algorithm->reset(new android::shared::VideoRenderAlgorithm(
- video_decoder_impl.get()));
- *video_renderer_sink = video_decoder_impl->GetSink();
- video_decoder->reset(video_decoder_impl.release());
- } else {
- video_decoder->reset();
- *video_renderer_sink = NULL;
- *error_message =
- "Failed to create video decoder with error: " + *error_message;
- return false;
- }
- }
-
- return true;
- }
-
- void GetAudioRendererParams(const CreationParameters& creation_parameters,
- int* max_cached_frames,
- int* min_frames_per_append) const override {
- SB_DCHECK(max_cached_frames);
- SB_DCHECK(min_frames_per_append);
- SB_DCHECK(kDefaultAudioSinkMinFramesPerAppend % kAudioSinkFramesAlignment ==
- 0);
- *min_frames_per_append = kDefaultAudioSinkMinFramesPerAppend;
-
- // AudioRenderer prefers to use kSbMediaAudioSampleTypeFloat32 and only uses
- // kSbMediaAudioSampleTypeInt16Deprecated when float32 is not supported.
- int min_frames_required = SbAudioSinkGetMinBufferSizeInFrames(
- creation_parameters.audio_sample_info().number_of_channels,
- SbAudioSinkIsAudioSampleTypeSupported(kSbMediaAudioSampleTypeFloat32)
- ? kSbMediaAudioSampleTypeFloat32
- : kSbMediaAudioSampleTypeInt16Deprecated,
- creation_parameters.audio_sample_info().samples_per_second);
- // On Android 5.0, the size of audio renderer sink buffer need to be two
- // times larger than AudioTrack minBufferSize. Otherwise, AudioTrack may
- // stop working after pause.
- *max_cached_frames =
- min_frames_required * 2 + kDefaultAudioSinkMinFramesPerAppend;
- *max_cached_frames = AlignUp(*max_cached_frames, kAudioSinkFramesAlignment);
- }
-};
-
-} // namespace
-
// static
scoped_ptr<PlayerComponents::Factory> PlayerComponents::Factory::Create() {
return make_scoped_ptr<PlayerComponents::Factory>(
- new PlayerComponentsFactory);
+ new android::shared::PlayerComponentsFactory);
}
// static
diff --git a/src/starboard/android/shared/player_components_factory.h b/src/starboard/android/shared/player_components_factory.h
new file mode 100644
index 0000000..350b00f
--- /dev/null
+++ b/src/starboard/android/shared/player_components_factory.h
@@ -0,0 +1,173 @@
+// Copyright 2017 The Cobalt Authors. 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_ANDROID_SHARED_PLAYER_COMPONENTS_FACTORY_H_
+#define STARBOARD_ANDROID_SHARED_PLAYER_COMPONENTS_FACTORY_H_
+
+#include <string>
+
+#include "starboard/android/shared/audio_decoder.h"
+#include "starboard/android/shared/video_decoder.h"
+#include "starboard/android/shared/video_render_algorithm.h"
+#include "starboard/common/log.h"
+#include "starboard/common/ref_counted.h"
+#include "starboard/common/scoped_ptr.h"
+#include "starboard/media.h"
+#include "starboard/shared/opus/opus_audio_decoder.h"
+#include "starboard/shared/starboard/player/filter/adaptive_audio_decoder_internal.h"
+#include "starboard/shared/starboard/player/filter/audio_decoder_internal.h"
+#include "starboard/shared/starboard/player/filter/audio_renderer_sink.h"
+#include "starboard/shared/starboard/player/filter/audio_renderer_sink_impl.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/filter/video_render_algorithm.h"
+#include "starboard/shared/starboard/player/filter/video_render_algorithm_impl.h"
+#include "starboard/shared/starboard/player/filter/video_renderer_sink.h"
+
+namespace starboard {
+namespace android {
+namespace shared {
+
+class PlayerComponentsFactory : public starboard::shared::starboard::player::
+ filter::PlayerComponents::Factory {
+ typedef starboard::shared::opus::OpusAudioDecoder OpusAudioDecoder;
+ typedef starboard::shared::starboard::player::filter::AdaptiveAudioDecoder
+ AdaptiveAudioDecoder;
+ typedef starboard::shared::starboard::player::filter::AudioDecoder
+ AudioDecoderBase;
+ typedef starboard::shared::starboard::player::filter::AudioRendererSink
+ AudioRendererSink;
+ typedef starboard::shared::starboard::player::filter::AudioRendererSinkImpl
+ AudioRendererSinkImpl;
+ typedef starboard::shared::starboard::player::filter::VideoDecoder
+ VideoDecoderBase;
+ typedef starboard::shared::starboard::player::filter::VideoRenderAlgorithm
+ VideoRenderAlgorithmBase;
+ typedef starboard::shared::starboard::player::filter::VideoRendererSink
+ VideoRendererSink;
+
+ const int kAudioSinkFramesAlignment = 256;
+ const int kDefaultAudioSinkMinFramesPerAppend = 1024;
+ const int kDefaultAudioSinkMaxCachedFrames =
+ 8 * kDefaultAudioSinkMinFramesPerAppend;
+
+ virtual SbDrmSystem GetExtendedDrmSystem(SbDrmSystem drm_system) {
+ return drm_system;
+ }
+
+ static int AlignUp(int value, int alignment) {
+ return (value + alignment - 1) / alignment * alignment;
+ }
+
+ bool CreateSubComponents(
+ const CreationParameters& creation_parameters,
+ scoped_ptr<AudioDecoderBase>* audio_decoder,
+ scoped_ptr<AudioRendererSink>* audio_renderer_sink,
+ scoped_ptr<VideoDecoderBase>* video_decoder,
+ scoped_ptr<VideoRenderAlgorithmBase>* video_render_algorithm,
+ scoped_refptr<VideoRendererSink>* video_renderer_sink,
+ std::string* error_message) override {
+ SB_DCHECK(error_message);
+
+ if (creation_parameters.audio_codec() != kSbMediaAudioCodecNone) {
+ SB_DCHECK(audio_decoder);
+ SB_DCHECK(audio_renderer_sink);
+
+ auto decoder_creator = [](const SbMediaAudioSampleInfo& audio_sample_info,
+ SbDrmSystem drm_system) {
+ if (audio_sample_info.codec == kSbMediaAudioCodecAac) {
+ scoped_ptr<AudioDecoder> audio_decoder_impl(new AudioDecoder(
+ audio_sample_info.codec, audio_sample_info, drm_system));
+ if (audio_decoder_impl->is_valid()) {
+ return audio_decoder_impl.PassAs<AudioDecoderBase>();
+ }
+ } else if (audio_sample_info.codec == kSbMediaAudioCodecOpus) {
+ scoped_ptr<OpusAudioDecoder> audio_decoder_impl(
+ new OpusAudioDecoder(audio_sample_info));
+ if (audio_decoder_impl->is_valid()) {
+ return audio_decoder_impl.PassAs<AudioDecoderBase>();
+ }
+ } else {
+ SB_NOTREACHED();
+ }
+ return scoped_ptr<AudioDecoderBase>();
+ };
+
+ audio_decoder->reset(new AdaptiveAudioDecoder(
+ creation_parameters.audio_sample_info(),
+ GetExtendedDrmSystem(creation_parameters.drm_system()),
+ decoder_creator));
+ audio_renderer_sink->reset(new AudioRendererSinkImpl);
+ }
+
+ if (creation_parameters.video_codec() != kSbMediaVideoCodecNone) {
+ SB_DCHECK(video_decoder);
+ SB_DCHECK(video_render_algorithm);
+ SB_DCHECK(video_renderer_sink);
+ SB_DCHECK(error_message);
+
+ scoped_ptr<VideoDecoder> video_decoder_impl(new VideoDecoder(
+ creation_parameters.video_codec(),
+ GetExtendedDrmSystem(creation_parameters.drm_system()),
+ creation_parameters.output_mode(),
+ creation_parameters.decode_target_graphics_context_provider(),
+ creation_parameters.max_video_capabilities(), error_message));
+ if (video_decoder_impl->is_valid()) {
+ video_render_algorithm->reset(
+ new VideoRenderAlgorithm(video_decoder_impl.get()));
+ *video_renderer_sink = video_decoder_impl->GetSink();
+ video_decoder->reset(video_decoder_impl.release());
+ } else {
+ video_decoder->reset();
+ *video_renderer_sink = NULL;
+ *error_message =
+ "Failed to create video decoder with error: " + *error_message;
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ void GetAudioRendererParams(const CreationParameters& creation_parameters,
+ int* max_cached_frames,
+ int* min_frames_per_append) const override {
+ SB_DCHECK(max_cached_frames);
+ SB_DCHECK(min_frames_per_append);
+ SB_DCHECK(kDefaultAudioSinkMinFramesPerAppend % kAudioSinkFramesAlignment ==
+ 0);
+ *min_frames_per_append = kDefaultAudioSinkMinFramesPerAppend;
+
+ // AudioRenderer prefers to use kSbMediaAudioSampleTypeFloat32 and only uses
+ // kSbMediaAudioSampleTypeInt16Deprecated when float32 is not supported.
+ int min_frames_required = SbAudioSinkGetMinBufferSizeInFrames(
+ creation_parameters.audio_sample_info().number_of_channels,
+ SbAudioSinkIsAudioSampleTypeSupported(kSbMediaAudioSampleTypeFloat32)
+ ? kSbMediaAudioSampleTypeFloat32
+ : kSbMediaAudioSampleTypeInt16Deprecated,
+ creation_parameters.audio_sample_info().samples_per_second);
+ // On Android 5.0, the size of audio renderer sink buffer need to be two
+ // times larger than AudioTrack minBufferSize. Otherwise, AudioTrack may
+ // stop working after pause.
+ *max_cached_frames =
+ min_frames_required * 2 + kDefaultAudioSinkMinFramesPerAppend;
+ *max_cached_frames = AlignUp(*max_cached_frames, kAudioSinkFramesAlignment);
+ }
+};
+
+} // namespace shared
+} // namespace android
+} // namespace starboard
+
+#endif // STARBOARD_ANDROID_SHARED_PLAYER_COMPONENTS_FACTORY_H_
diff --git a/src/starboard/android/shared/player_create.cc b/src/starboard/android/shared/player_create.cc
index a3a9a2a..a3ff14b 100644
--- a/src/starboard/android/shared/player_create.cc
+++ b/src/starboard/android/shared/player_create.cc
@@ -14,7 +14,6 @@
#include "starboard/player.h"
-#include "starboard/android/shared/android_media_session_client.h"
#include "starboard/android/shared/video_decoder.h"
#include "starboard/android/shared/video_window.h"
#include "starboard/common/log.h"
@@ -28,8 +27,6 @@
using starboard::shared::starboard::player::filter::
FilterBasedPlayerWorkerHandler;
using starboard::shared::starboard::player::PlayerWorker;
-using starboard::android::shared::kPlaying;
-using starboard::android::shared::UpdateActiveSessionPlatformPlaybackState;
using starboard::android::shared::VideoDecoder;
SbPlayer SbPlayerCreate(SbWindow window,
@@ -125,8 +122,6 @@
kMaxNumberOfHardwareDecoders) {
return kSbPlayerInvalid;
}
- // Only update session state for main player.
- UpdateActiveSessionPlatformPlaybackState(kPlaying);
}
if (creation_param->output_mode != kSbPlayerOutputModeDecodeToTexture &&
diff --git a/src/starboard/android/shared/player_destroy.cc b/src/starboard/android/shared/player_destroy.cc
index bdfbba3..6a1a293 100644
--- a/src/starboard/android/shared/player_destroy.cc
+++ b/src/starboard/android/shared/player_destroy.cc
@@ -14,16 +14,12 @@
#include "starboard/player.h"
-#include "starboard/android/shared/android_media_session_client.h"
#include "starboard/shared/starboard/player/player_internal.h"
-using starboard::android::shared::kNone;
-using starboard::android::shared::UpdateActiveSessionPlatformPlaybackState;
-
void SbPlayerDestroy(SbPlayer player) {
if (!SbPlayerIsValid(player)) {
return;
}
- UpdateActiveSessionPlatformPlaybackState(kNone);
+
delete player;
}
diff --git a/src/starboard/android/shared/player_set_playback_rate.cc b/src/starboard/android/shared/player_set_playback_rate.cc
index 233cd92..d18c197 100644
--- a/src/starboard/android/shared/player_set_playback_rate.cc
+++ b/src/starboard/android/shared/player_set_playback_rate.cc
@@ -14,14 +14,9 @@
#include "starboard/player.h"
-#include "starboard/android/shared/android_media_session_client.h"
#include "starboard/common/log.h"
#include "starboard/shared/starboard/player/player_internal.h"
-using starboard::android::shared::kPaused;
-using starboard::android::shared::kPlaying;
-using starboard::android::shared::UpdateActiveSessionPlatformPlaybackState;
-
bool SbPlayerSetPlaybackRate(SbPlayer player, double playback_rate) {
if (!SbPlayerIsValid(player)) {
SB_DLOG(WARNING) << "player is invalid.";
@@ -32,8 +27,6 @@
<< playback_rate << '.';
return false;
}
- bool paused = (playback_rate == 0.0);
- UpdateActiveSessionPlatformPlaybackState(paused ? kPaused : kPlaying);
player->SetPlaybackRate(playback_rate);
return true;
diff --git a/src/starboard/android/shared/starboard_platform.gypi b/src/starboard/android/shared/starboard_platform.gypi
index 65c5044..d38907b 100644
--- a/src/starboard/android/shared/starboard_platform.gypi
+++ b/src/starboard/android/shared/starboard_platform.gypi
@@ -135,6 +135,7 @@
'media_is_audio_supported.cc',
'media_is_video_supported.cc',
'microphone_impl.cc',
+ 'player_components_factory.h',
'player_create.cc',
'player_destroy.cc',
'player_get_preferred_output_mode.cc',
diff --git a/src/starboard/android/x86/cobalt/configuration.py b/src/starboard/android/x86/cobalt/configuration.py
index 5e11fd8..64509ee 100644
--- a/src/starboard/android/x86/cobalt/configuration.py
+++ b/src/starboard/android/x86/cobalt/configuration.py
@@ -43,14 +43,6 @@
'CSS3FontsLayoutTests/Layout.Test'
'/synthetic_bolding_should_occur_on_non_bold_font',
],
- 'nb_test': [
- 'BidirectionalFitReuseAllocatorTest.FallbackBlockMerge',
- 'BidirectionalFitReuseAllocatorTest.FreeBlockMergingLeft',
- 'BidirectionalFitReuseAllocatorTest.FreeBlockMergingRight',
- 'FirstFitReuseAllocatorTest.FallbackBlockMerge',
- 'FirstFitReuseAllocatorTest.FreeBlockMergingLeft',
- 'FirstFitReuseAllocatorTest.FreeBlockMergingRight',
- ],
'net_unittests': [ # Net tests are very unstable on Android L
test_filter.FILTER_ALL
],
diff --git a/src/starboard/build/platform_configuration.py b/src/starboard/build/platform_configuration.py
index ebb054e..eaf4088 100644
--- a/src/starboard/build/platform_configuration.py
+++ b/src/starboard/build/platform_configuration.py
@@ -22,7 +22,7 @@
from starboard.build.application_configuration import ApplicationConfiguration
from starboard.optional import get_optional_tests
from starboard.sabi import sabi
-from starboard.tools import ccache
+from starboard.tools import cache
from starboard.tools import environment
from starboard.tools import paths
from starboard.tools import platform
@@ -70,15 +70,19 @@
self._directory = os.path.realpath(os.path.dirname(__file__))
self._application_configuration = None
self._application_configuration_search_path = [self._directory]
+ # Default build accelerator is ccache.
+ self.build_accelerator = self.GetBuildAccelerator(cache.Accelerator.CCACHE)
- # Specifies the build accelerator to be used. Default is ccache.
- build_accelerator = ccache.Ccache()
+ def GetBuildAccelerator(self, accelerator):
+ """Returns the build accelerator name."""
+ build_accelerator = cache.Cache(accelerator)
+ name = build_accelerator.GetName()
if build_accelerator.Use():
- self.build_accelerator = build_accelerator.GetName()
- logging.info('Using %sbuild accelerator.', self.build_accelerator)
+ logging.info('Using %s build accelerator.', name)
+ return name
else:
- self.build_accelerator = ''
- logging.info('Not using a build accelerator.')
+ logging.info('Not using %s build accelerator.', name)
+ return ''
def GetBuildFormat(self):
"""Returns the desired build format."""
@@ -354,7 +358,8 @@
raise NotImplementedError()
def GetPathToSabiJsonFile(self):
- """Gets the path to the JSON file with Starboard ABI information for the build.
+ """Gets the path to the JSON file with Starboard ABI information for the
+ build.
Examples:
'starboard/sabi/arm64/sabi-v12.json'
diff --git a/src/starboard/common/configuration_defaults.cc b/src/starboard/common/configuration_defaults.cc
index d603e4f..6a933b9 100644
--- a/src/starboard/common/configuration_defaults.cc
+++ b/src/starboard/common/configuration_defaults.cc
@@ -30,7 +30,7 @@
}
const char* CobaltFallbackSplashScreenUrlDefault() {
- return "none";
+ return "h5vcc-embedded://black_splash_screen.html";
}
const char* CobaltFallbackSplashScreenTopicsDefault() {
diff --git a/src/starboard/common/mutex.h b/src/starboard/common/mutex.h
index 67f1b68..6012c55 100644
--- a/src/starboard/common/mutex.h
+++ b/src/starboard/common/mutex.h
@@ -52,7 +52,8 @@
SbMutex* mutex() const;
mutable SbMutex mutex_;
- SB_DISALLOW_COPY_AND_ASSIGN(Mutex);
+ Mutex(const Mutex&) = delete;
+ void operator=(const Mutex&) = delete;
};
// Scoped lock holder that works on starboard::Mutex.
@@ -63,7 +64,9 @@
private:
const Mutex& mutex_;
- SB_DISALLOW_COPY_AND_ASSIGN(ScopedLock);
+
+ ScopedLock(const ScopedLock&) = delete;
+ void operator=(const ScopedLock&) = delete;
};
// Scoped lock holder that works on starboard::Mutex which uses AcquireTry()
@@ -78,7 +81,9 @@
private:
const Mutex& mutex_;
bool is_locked_;
- SB_DISALLOW_COPY_AND_ASSIGN(ScopedTryLock);
+
+ ScopedTryLock(const ScopedTryLock&) = delete;
+ void operator=(const ScopedTryLock&) = delete;
};
} // namespace starboard
diff --git a/src/starboard/common/recursive_mutex.h b/src/starboard/common/recursive_mutex.h
index b949da9..6806858 100644
--- a/src/starboard/common/recursive_mutex.h
+++ b/src/starboard/common/recursive_mutex.h
@@ -48,7 +48,8 @@
// Only the owner is able to modify recurse_count_.
size_t recurse_count_;
- SB_DISALLOW_COPY_AND_ASSIGN(RecursiveMutex);
+ RecursiveMutex(const RecursiveMutex&) = delete;
+ void operator=(const RecursiveMutex&) = delete;
};
class ScopedRecursiveLock {
@@ -58,7 +59,9 @@
private:
RecursiveMutex& mutex_;
- SB_DISALLOW_COPY_AND_ASSIGN(ScopedRecursiveLock);
+
+ ScopedRecursiveLock(const ScopedRecursiveLock&) = delete;
+ void operator=(const ScopedRecursiveLock&) = delete;
};
} // namespace starboard
diff --git a/src/starboard/common/rwlock.h b/src/starboard/common/rwlock.h
index 2ec8d05..73aafdd 100644
--- a/src/starboard/common/rwlock.h
+++ b/src/starboard/common/rwlock.h
@@ -68,7 +68,8 @@
int32_t readers_;
bool writing_;
- SB_DISALLOW_COPY_AND_ASSIGN(RWLock);
+ RWLock(const RWLock&) = delete;
+ void operator=(const RWLock&) = delete;
};
class ScopedReadLock {
@@ -80,7 +81,9 @@
private:
RWLock* rw_lock_;
- SB_DISALLOW_COPY_AND_ASSIGN(ScopedReadLock);
+
+ ScopedReadLock(const ScopedReadLock&) = delete;
+ void operator=(const ScopedReadLock&) = delete;
};
class ScopedWriteLock {
@@ -92,7 +95,9 @@
private:
RWLock* rw_lock_;
- SB_DISALLOW_COPY_AND_ASSIGN(ScopedWriteLock);
+
+ ScopedWriteLock(const ScopedWriteLock&) = delete;
+ void operator=(const ScopedWriteLock&) = delete;
};
} // namespace starboard
diff --git a/src/starboard/common/semaphore.h b/src/starboard/common/semaphore.h
index 35ad34a..ce0f800 100644
--- a/src/starboard/common/semaphore.h
+++ b/src/starboard/common/semaphore.h
@@ -52,7 +52,8 @@
ConditionVariable condition_;
int permits_;
- SB_DISALLOW_COPY_AND_ASSIGN(Semaphore);
+ Semaphore(const Semaphore&) = delete;
+ void operator=(const Semaphore&) = delete;
};
} // namespace starboard.
diff --git a/src/starboard/common/thread.h b/src/starboard/common/thread.h
index 1a878a0..c01b817 100644
--- a/src/starboard/common/thread.h
+++ b/src/starboard/common/thread.h
@@ -77,7 +77,8 @@
struct Data;
scoped_ptr<Data> d_;
- SB_DISALLOW_COPY_AND_ASSIGN(Thread);
+ Thread(const Thread&) = delete;
+ void operator=(const Thread&) = delete;
};
} // namespace starboard
diff --git a/src/starboard/configuration.h b/src/starboard/configuration.h
index e82f471..9a4477a 100644
--- a/src/starboard/configuration.h
+++ b/src/starboard/configuration.h
@@ -31,9 +31,6 @@
#error "You must define STARBOARD in Starboard builds."
#endif
-#define SB_TRUE 1
-#define SB_FALSE 0
-
// --- Common Defines --------------------------------------------------------
// The minimum API version allowed by this version of the Starboard headers,
@@ -77,6 +74,13 @@
// Deprecated the SB_OVERRIDE macro.
#define SB_OVERRIDE_DEPRECATED_VERSION SB_EXPERIMENTAL_API_VERSION
+// Deprecated the SB_DISALLOW_COPY_AND_ASSIGN macro.
+#define SB_DISALLOW_COPY_AND_ASSIGN_DEPRECATED_VERSION \
+ SB_EXPERIMENTAL_API_VERSION
+
+// Deprecated SB_TRUE and SB_FALSE.
+#define SB_TRUE_FALSE_DEPRECATED_VERSION SB_EXPERIMENTAL_API_VERSION
+
// --- Release Candidate Feature Defines -------------------------------------
// --- Common Detected Features ----------------------------------------------
@@ -89,6 +93,14 @@
// --- Common Helper Macros --------------------------------------------------
+#if SB_API_VERSION < SB_TRUE_FALSE_DEPRECATED_VERSION
+#define SB_TRUE 1
+#define SB_FALSE 0
+#else
+#define SB_TRUE #error "The macro SB_TRUE is deprecated."
+#define SB_FALSE #error "The macro SB_FALSE is deprecated."
+#endif
+
// Determines a compile-time capability of the system.
#define SB_CAN(SB_FEATURE) \
((defined SB_CAN_##SB_FEATURE) && SB_CAN_##SB_FEATURE)
@@ -146,11 +158,16 @@
#define SB_STRINGIFY(x) SB_STRINGIFY2(x)
#define SB_STRINGIFY2(x) #x
+#if SB_API_VERSION < SB_DISALLOW_COPY_AND_ASSIGN_DEPRECATED_VERSION
// A macro to disallow the copy constructor and operator= functions
// This should be used in the private: declarations for a class
#define SB_DISALLOW_COPY_AND_ASSIGN(TypeName) \
TypeName(const TypeName&) = delete; \
void operator=(const TypeName&) = delete
+#else
+#define SB_DISALLOW_COPY_AND_ASSIGN \
+ #error "The SB_DISALLOW_COPY_AND_ASSIGN macro is deprecated."
+#endif // SB_DISALLOW_COPY_AND_ASSIGN_DEPRECATED_VERSION < SB_API_VERSION
// An enumeration of values for the kSbPreferredByteOrder configuration
// variable. Setting this up properly means avoiding slow color swizzles when
@@ -598,16 +615,13 @@
#if defined(SB_MEDIA_MAXIMUM_VIDEO_FRAMES)
#error \
"SB_MEDIA_MAXIMUM_VIDEO_FRAMES should not be defined in Starboard " \
-"versions 12 and later. Instead, define kSbMediaMaximumVideoFrames in " \
-"starboard/<PLATFORM_PATH>/configuration_constants.cc."
+"versions 12 and later."
#endif
#if defined(SB_MEDIA_MAXIMUM_VIDEO_PREROLL_FRAMES)
#error \
"SB_MEDIA_MAXIMUM_VIDEO_PREROLL_FRAMES should not be defined in " \
-"Starboard versions 12 and later. Instead, define " \
-"kSbMediaMaximumVideoPrerollFrames in " \
-"starboard/<PLATFORM_PATH>/configuration_constants.cc."
+"Starboard versions 12 and later."
#endif
#if defined(SB_MEDIA_MAX_AUDIO_BITRATE_IN_BITS_PER_SECOND)
diff --git a/src/starboard/configuration_constants.h b/src/starboard/configuration_constants.h
index 961affe..1a1aac4 100644
--- a/src/starboard/configuration_constants.h
+++ b/src/starboard/configuration_constants.h
@@ -93,21 +93,6 @@
// video.
extern const uint32_t kSbMediaMaxVideoBitrateInBitsPerSecond;
-// Specify the number of video frames to be cached during playback. A large
-// value leads to more stable fps but also causes the app to use more memory.
-extern const uint32_t kSbMediaMaximumVideoFrames;
-
-// The encoded video frames are compressed in different ways, so their decoding
-// time can vary a lot. Occasionally a single frame can take longer time to
-// decode than the average time per frame. The player has to cache some frames
-// to account for such inconsistency. The number of frames being cached are
-// controlled by SB_MEDIA_MAXIMUM_VIDEO_PREROLL_FRAMES and
-// SB_MEDIA_MAXIMUM_VIDEO_FRAMES.
-//
-// Specify the number of video frames to be cached before the playback starts.
-// Note that setting this value too large may increase the playback start delay.
-extern const uint32_t kSbMediaMaximumVideoPrerollFrames;
-
// Specifies how video frame buffers must be aligned on this platform.
extern const uint32_t kSbMediaVideoFrameAlignment;
diff --git a/src/starboard/contrib/tizen/armv7l/configuration_public.h b/src/starboard/contrib/tizen/armv7l/configuration_public.h
index d3c0233..c4902db 100644
--- a/src/starboard/contrib/tizen/armv7l/configuration_public.h
+++ b/src/starboard/contrib/tizen/armv7l/configuration_public.h
@@ -126,14 +126,6 @@
// decode than the average time per frame. The player has to cache some frames
// to account for such inconsistency. The number of frames being cached are
// controlled by the following two macros.
-//
-// Specify the number of video frames to be cached before the playback starts.
-// Note that set this value too large may increase the playback start delay.
-#define SB_MEDIA_MAXIMUM_VIDEO_PREROLL_FRAMES 4
-
-// Specify the number of video frames to be cached during playback. A large
-// value leads to more stable fps but also causes the app to use more memory.
-#define SB_MEDIA_MAXIMUM_VIDEO_FRAMES 12
// --- Timing API ------------------------------------------------------------
diff --git a/src/starboard/elf_loader/dynamic_section.h b/src/starboard/elf_loader/dynamic_section.h
index 8d22bf1..6619b90 100644
--- a/src/starboard/elf_loader/dynamic_section.h
+++ b/src/starboard/elf_loader/dynamic_section.h
@@ -90,7 +90,8 @@
linker_function_t init_func_;
linker_function_t fini_func_;
- SB_DISALLOW_COPY_AND_ASSIGN(DynamicSection);
+ DynamicSection(const DynamicSection&) = delete;
+ void operator=(const DynamicSection&) = delete;
};
} // namespace elf_loader
diff --git a/src/starboard/elf_loader/elf_hash_table.h b/src/starboard/elf_loader/elf_hash_table.h
index 14bb9ca..7a867c1 100644
--- a/src/starboard/elf_loader/elf_hash_table.h
+++ b/src/starboard/elf_loader/elf_hash_table.h
@@ -53,7 +53,8 @@
const Word* hash_chain_;
size_t hash_chain_size_;
- SB_DISALLOW_COPY_AND_ASSIGN(ElfHashTable);
+ ElfHashTable(const ElfHashTable&) = delete;
+ void operator=(const ElfHashTable&) = delete;
};
} // namespace elf_loader
diff --git a/src/starboard/elf_loader/elf_header.h b/src/starboard/elf_loader/elf_header.h
index a8b666c..647a1bf 100644
--- a/src/starboard/elf_loader/elf_header.h
+++ b/src/starboard/elf_loader/elf_header.h
@@ -36,7 +36,9 @@
private:
scoped_ptr<Ehdr> elf_header_;
- SB_DISALLOW_COPY_AND_ASSIGN(ElfHeader);
+
+ ElfHeader(const ElfHeader&) = delete;
+ void operator=(const ElfHeader&) = delete;
};
} // namespace elf_loader
diff --git a/src/starboard/elf_loader/elf_loader.h b/src/starboard/elf_loader/elf_loader.h
index 7119651..587c7a6 100644
--- a/src/starboard/elf_loader/elf_loader.h
+++ b/src/starboard/elf_loader/elf_loader.h
@@ -66,7 +66,8 @@
// The single ELF Loader instance.
static ElfLoader* g_instance;
- SB_DISALLOW_COPY_AND_ASSIGN(ElfLoader);
+ ElfLoader(const ElfLoader&) = delete;
+ void operator=(const ElfLoader&) = delete;
};
} // namespace elf_loader
diff --git a/src/starboard/elf_loader/elf_loader_impl.h b/src/starboard/elf_loader/elf_loader_impl.h
index da9c5f3..84c43c7 100644
--- a/src/starboard/elf_loader/elf_loader_impl.h
+++ b/src/starboard/elf_loader/elf_loader_impl.h
@@ -46,7 +46,8 @@
scoped_ptr<ExportedSymbols> exported_symbols_;
scoped_ptr<Relocations> relocations_;
- SB_DISALLOW_COPY_AND_ASSIGN(ElfLoaderImpl);
+ ElfLoaderImpl(const ElfLoaderImpl&) = delete;
+ void operator=(const ElfLoaderImpl&) = delete;
};
} // namespace elf_loader
diff --git a/src/starboard/elf_loader/elf_loader_sys_impl.h b/src/starboard/elf_loader/elf_loader_sys_impl.h
index bcc7af0..7f148a5 100644
--- a/src/starboard/elf_loader/elf_loader_sys_impl.h
+++ b/src/starboard/elf_loader/elf_loader_sys_impl.h
@@ -32,7 +32,8 @@
private:
void* handle_;
- SB_DISALLOW_COPY_AND_ASSIGN(ElfLoaderImpl);
+ ElfLoaderImpl(const ElfLoaderImpl&) = delete;
+ void operator=(const ElfLoaderImpl&) = delete;
};
} // namespace elf_loader
diff --git a/src/starboard/elf_loader/evergreen_config.h b/src/starboard/elf_loader/evergreen_config.h
index a2ca212..6078b43 100644
--- a/src/starboard/elf_loader/evergreen_config.h
+++ b/src/starboard/elf_loader/evergreen_config.h
@@ -48,7 +48,8 @@
EvergreenConfig(const char* library_path,
const char* content_path,
const void* (*custom_get_extension_)(const char* name));
- SB_DISALLOW_COPY_AND_ASSIGN(EvergreenConfig);
+ EvergreenConfig(const EvergreenConfig&) = delete;
+ void operator=(const EvergreenConfig&) = delete;
};
} // namespace elf_loader
diff --git a/src/starboard/elf_loader/exported_symbols.cc b/src/starboard/elf_loader/exported_symbols.cc
index b07c021..33e24f0 100644
--- a/src/starboard/elf_loader/exported_symbols.cc
+++ b/src/starboard/elf_loader/exported_symbols.cc
@@ -447,8 +447,6 @@
REGISTER_SYMBOL(kSbMaxThreadNameLength);
REGISTER_SYMBOL(kSbMediaMaxAudioBitrateInBitsPerSecond);
REGISTER_SYMBOL(kSbMediaMaxVideoBitrateInBitsPerSecond);
- REGISTER_SYMBOL(kSbMediaMaximumVideoFrames);
- REGISTER_SYMBOL(kSbMediaMaximumVideoPrerollFrames);
REGISTER_SYMBOL(kSbMediaVideoFrameAlignment);
REGISTER_SYMBOL(kSbMemoryLogPath);
REGISTER_SYMBOL(kSbMemoryPageSize);
diff --git a/src/starboard/elf_loader/exported_symbols.h b/src/starboard/elf_loader/exported_symbols.h
index 1ffc732..e246214 100644
--- a/src/starboard/elf_loader/exported_symbols.h
+++ b/src/starboard/elf_loader/exported_symbols.h
@@ -41,7 +41,8 @@
private:
std::map<std::string, const void*> map_;
- SB_DISALLOW_COPY_AND_ASSIGN(ExportedSymbols);
+ ExportedSymbols(const ExportedSymbols&) = delete;
+ void operator=(const ExportedSymbols&) = delete;
};
} // namespace elf_loader
diff --git a/src/starboard/elf_loader/file_impl.h b/src/starboard/elf_loader/file_impl.h
index 9407c95..8545195 100644
--- a/src/starboard/elf_loader/file_impl.h
+++ b/src/starboard/elf_loader/file_impl.h
@@ -35,7 +35,8 @@
private:
SbFile file_;
- SB_DISALLOW_COPY_AND_ASSIGN(FileImpl);
+ FileImpl(const FileImpl&) = delete;
+ void operator=(const FileImpl&) = delete;
};
} // namespace elf_loader
diff --git a/src/starboard/elf_loader/gnu_hash_table.h b/src/starboard/elf_loader/gnu_hash_table.h
index 5bdf199..bf08c17 100644
--- a/src/starboard/elf_loader/gnu_hash_table.h
+++ b/src/starboard/elf_loader/gnu_hash_table.h
@@ -57,7 +57,8 @@
const uint32_t* buckets_;
const uint32_t* chain_;
- SB_DISALLOW_COPY_AND_ASSIGN(GnuHashTable);
+ GnuHashTable(const GnuHashTable&) = delete;
+ void operator=(const GnuHashTable&) = delete;
};
} // namespace elf_loader
diff --git a/src/starboard/elf_loader/program_table.h b/src/starboard/elf_loader/program_table.h
index d08301c..3741002 100644
--- a/src/starboard/elf_loader/program_table.h
+++ b/src/starboard/elf_loader/program_table.h
@@ -90,7 +90,8 @@
// from the ELF file are offsets from this address.
Addr base_memory_address_;
- SB_DISALLOW_COPY_AND_ASSIGN(ProgramTable);
+ ProgramTable(const ProgramTable&) = delete;
+ void operator=(const ProgramTable&) = delete;
};
} // namespace elf_loader
diff --git a/src/starboard/elf_loader/relocations.h b/src/starboard/elf_loader/relocations.h
index fad8a4e..1058c19 100644
--- a/src/starboard/elf_loader/relocations.h
+++ b/src/starboard/elf_loader/relocations.h
@@ -84,7 +84,8 @@
ExportedSymbols* exported_symbols_;
- SB_DISALLOW_COPY_AND_ASSIGN(Relocations);
+ Relocations(const Relocations&) = delete;
+ void operator=(const Relocations&) = delete;
};
} // namespace elf_loader
diff --git a/src/starboard/evergreen/arm64/configuration_public.h b/src/starboard/evergreen/arm64/configuration_public.h
index 211ccc1..243ed7c 100644
--- a/src/starboard/evergreen/arm64/configuration_public.h
+++ b/src/starboard/evergreen/arm64/configuration_public.h
@@ -23,10 +23,6 @@
// --- Architecture Configuration --------------------------------------------
-// Indicates that there is no support for alignment at greater than 16 bytes for
-// items on the stack.
-#define SB_HAS_QUIRK_DOES_NOT_STACK_ALIGN_OVER_16_BYTES 1
-
// --- System Header Configuration -------------------------------------------
// Any system headers listed here that are not provided by the platform will be
@@ -141,16 +137,16 @@
// --- Memory Configuration --------------------------------------------------
+// Whether this platform can map executable memory. Implies SB_HAS_MMAP. This is
+// required for platforms that want to JIT.
+#define SB_CAN_MAP_EXECUTABLE_MEMORY 1
+
// Whether this platform has and should use an MMAP function to map physical
// memory to the virtual address space.
#if SB_API_VERSION < 12
#define SB_HAS_MMAP 1
#endif
-// Whether this platform can map executable memory. Implies SB_HAS_MMAP. This is
-// required for platforms that want to JIT.
-#define SB_CAN_MAP_EXECUTABLE_MEMORY 1
-
// --- Network Configuration -------------------------------------------------
// Specifies whether this platform supports IPV6.
@@ -177,4 +173,10 @@
#error "Evergreen-arm64 builds need a GCC-like compiler (for the moment)."
#endif
+// --- Platform Specific Quirks ----------------------------------------------
+
+// Indicates that there is no support for alignment at greater than 16 bytes for
+// items on the stack.
+#define SB_HAS_QUIRK_DOES_NOT_STACK_ALIGN_OVER_16_BYTES 1
+
#endif // STARBOARD_EVERGREEN_ARM64_CONFIGURATION_PUBLIC_H_
diff --git a/src/starboard/evergreen/testing/tests/abort_update_if_already_updating_test.sh b/src/starboard/evergreen/testing/tests/abort_update_if_already_updating_test.sh
index 7610aba..3061fb6 100755
--- a/src/starboard/evergreen/testing/tests/abort_update_if_already_updating_test.sh
+++ b/src/starboard/evergreen/testing/tests/abort_update_if_already_updating_test.sh
@@ -25,7 +25,7 @@
function run_test() {
clear_storage
- start_cobalt "file:///tests/${TEST_FILE}?channel=test" "${TEST_NAME}.0.log" "Created drain file"
+ start_cobalt "file:///tests/${TEST_FILE}?channel=test" "${TEST_NAME}.0.log" "Created drain file at"
if [[ $? -ne 0 ]]; then
error "Failed to create a drain file for the test package"
diff --git a/src/starboard/evergreen/testing/tests/alternative_content_test.sh b/src/starboard/evergreen/testing/tests/alternative_content_test.sh
index 51ac20b..c962b8e 100755
--- a/src/starboard/evergreen/testing/tests/alternative_content_test.sh
+++ b/src/starboard/evergreen/testing/tests/alternative_content_test.sh
@@ -25,7 +25,7 @@
function run_test() {
clear_storage
- start_cobalt "file:///tests/${TEST_FILE}?channel=test" "${TEST_NAME}.0.log" "update from test channel installed"
+ start_cobalt "file:///tests/${TEST_FILE}?channel=test" "${TEST_NAME}.0.log" "update from test channel was installed"
if [[ $? -ne 0 ]]; then
error "Failed to download and install the test package"
diff --git a/src/starboard/evergreen/testing/tests/crashing_binary_test.sh b/src/starboard/evergreen/testing/tests/crashing_binary_test.sh
index 67a3f9a..c485690 100755
--- a/src/starboard/evergreen/testing/tests/crashing_binary_test.sh
+++ b/src/starboard/evergreen/testing/tests/crashing_binary_test.sh
@@ -25,7 +25,7 @@
function run_test() {
clear_storage
- start_cobalt "file:///tests/${TEST_FILE}?channel=tcrash" "${TEST_NAME}.0.log" "update from tcrash channel installed"
+ start_cobalt "file:///tests/${TEST_FILE}?channel=tcrash" "${TEST_NAME}.0.log" "update from tcrash channel was installed"
if [[ $? -ne 0 ]]; then
error "Failed to download and install the tcrash package"
diff --git a/src/starboard/evergreen/testing/tests/disabled_updater_test.sh b/src/starboard/evergreen/testing/tests/disabled_updater_test.sh
index 93275c5..9ba2528 100755
--- a/src/starboard/evergreen/testing/tests/disabled_updater_test.sh
+++ b/src/starboard/evergreen/testing/tests/disabled_updater_test.sh
@@ -25,7 +25,7 @@
function run_test() {
clear_storage
- start_cobalt "file:///tests/${TEST_FILE}?channel=test" "${TEST_NAME}.0.log" "update from test channel installed"
+ start_cobalt "file:///tests/${TEST_FILE}?channel=test" "${TEST_NAME}.0.log" "update from test channel was installed"
if [[ $? -ne 0 ]]; then
error "Failed to download and install the test package"
diff --git a/src/starboard/evergreen/testing/tests/load_slot_being_updated_test.sh b/src/starboard/evergreen/testing/tests/load_slot_being_updated_test.sh
index fdb73b0..d0b206f 100755
--- a/src/starboard/evergreen/testing/tests/load_slot_being_updated_test.sh
+++ b/src/starboard/evergreen/testing/tests/load_slot_being_updated_test.sh
@@ -25,7 +25,7 @@
function run_test() {
clear_storage
- start_cobalt "file:///tests/${TEST_FILE}?channel=test" "${TEST_NAME}.0.log" "update from test channel installed"
+ start_cobalt "file:///tests/${TEST_FILE}?channel=test" "${TEST_NAME}.0.log" "update from test channel was installed"
if [[ $? -ne 0 ]]; then
error "Failed to download and install the test package"
diff --git a/src/starboard/evergreen/testing/tests/mismatched_architecture_test.sh b/src/starboard/evergreen/testing/tests/mismatched_architecture_test.sh
index 00cc6da..6a90b12 100755
--- a/src/starboard/evergreen/testing/tests/mismatched_architecture_test.sh
+++ b/src/starboard/evergreen/testing/tests/mismatched_architecture_test.sh
@@ -25,7 +25,7 @@
function run_test() {
clear_storage
- start_cobalt "file:///tests/${TEST_FILE}?channel=tmsabi" "${TEST_NAME}.0.log" "update from tmsabi channel installed"
+ start_cobalt "file:///tests/${TEST_FILE}?channel=tmsabi" "${TEST_NAME}.0.log" "update from tmsabi channel was installed"
if [[ $? -ne 0 ]]; then
error "Failed to download and install the tmsabi package"
diff --git a/src/starboard/evergreen/testing/tests/noop_binary_test.sh b/src/starboard/evergreen/testing/tests/noop_binary_test.sh
index 0eb7cae..fd33059 100755
--- a/src/starboard/evergreen/testing/tests/noop_binary_test.sh
+++ b/src/starboard/evergreen/testing/tests/noop_binary_test.sh
@@ -25,7 +25,7 @@
function run_test() {
clear_storage
- start_cobalt "file:///tests/${TEST_FILE}?channel=tnoop" "${TEST_NAME}.0.log" "update from tnoop channel installed"
+ start_cobalt "file:///tests/${TEST_FILE}?channel=tnoop" "${TEST_NAME}.0.log" "update from tnoop channel was installed"
if [[ $? -ne 0 ]]; then
error "Failed to download and install the tnoop package"
diff --git a/src/starboard/evergreen/testing/tests/quick_roll_forward_test.sh b/src/starboard/evergreen/testing/tests/quick_roll_forward_test.sh
index 7dc28fe..789cbb6 100755
--- a/src/starboard/evergreen/testing/tests/quick_roll_forward_test.sh
+++ b/src/starboard/evergreen/testing/tests/quick_roll_forward_test.sh
@@ -25,7 +25,7 @@
function run_test() {
clear_storage
- start_cobalt "file:///tests/${TEST_FILE}?channel=test" "${TEST_NAME}.0.log" "update from test channel installed"
+ start_cobalt "file:///tests/${TEST_FILE}?channel=test" "${TEST_NAME}.0.log" "update from test channel was installed"
if [[ $? -ne 0 ]]; then
error "Failed to download and install the test package"
diff --git a/src/starboard/evergreen/testing/tests/racing_updaters_test.sh b/src/starboard/evergreen/testing/tests/racing_updaters_test.sh
index 2865095..6d3cde6 100755
--- a/src/starboard/evergreen/testing/tests/racing_updaters_test.sh
+++ b/src/starboard/evergreen/testing/tests/racing_updaters_test.sh
@@ -44,7 +44,7 @@
function run_test() {
clear_storage
- start_cobalt "file:///tests/${TEST_FILE}?channel=test" "${TEST_NAME}.0.log" "Created drain file"
+ start_cobalt "file:///tests/${TEST_FILE}?channel=test" "${TEST_NAME}.0.log" "Created drain file at"
if [[ $? -ne 0 ]]; then
error "Failed to create a drain file for the test package"
@@ -60,7 +60,7 @@
clear_storage
- wait_and_force_race_condition "Created drain file" "${LOG_PATH}/${TEST_NAME}.1.log" "${FILENAME}" &
+ wait_and_force_race_condition "Created drain file at" "${LOG_PATH}/${TEST_NAME}.1.log" "${FILENAME}" &
start_cobalt "file:///tests/${TEST_FILE}?channel=test" "${TEST_NAME}.1.log" "failed to lock slot"
diff --git a/src/starboard/evergreen/testing/tests/test.html b/src/starboard/evergreen/testing/tests/test.html
index 81a943c..d0b47f3 100644
--- a/src/starboard/evergreen/testing/tests/test.html
+++ b/src/starboard/evergreen/testing/tests/test.html
@@ -37,8 +37,10 @@
return;
}
- if (currentChannel == targetChannel) {
- console.log("update from " + targetChannel + " channel installed");
+ if (status == "Update installed, pending restart") {
+ clearInterval(changeChannel);
+ console.log("update from " + currentChannel + " channel was installed");
+ return;
}
}
diff --git a/src/starboard/evergreen/testing/tests/update_works_for_only_one_app_test.sh b/src/starboard/evergreen/testing/tests/update_works_for_only_one_app_test.sh
index 65e5ad0..7565d99 100755
--- a/src/starboard/evergreen/testing/tests/update_works_for_only_one_app_test.sh
+++ b/src/starboard/evergreen/testing/tests/update_works_for_only_one_app_test.sh
@@ -25,7 +25,7 @@
function run_test() {
clear_storage
- start_cobalt "file:///tests/${TEST_FILE}?channel=test" "${TEST_NAME}.0.log" "update from test channel installed"
+ start_cobalt "file:///tests/${TEST_FILE}?channel=test" "${TEST_NAME}.0.log" "update from test channel was installed"
if [[ $? -ne 0 ]]; then
error "Failed to download and install the test package"
diff --git a/src/starboard/evergreen/testing/tests/valid_slot_overwritten_test.sh b/src/starboard/evergreen/testing/tests/valid_slot_overwritten_test.sh
index 5fe2228..57379c4 100755
--- a/src/starboard/evergreen/testing/tests/valid_slot_overwritten_test.sh
+++ b/src/starboard/evergreen/testing/tests/valid_slot_overwritten_test.sh
@@ -25,7 +25,7 @@
function run_test() {
clear_storage
- start_cobalt "file:///tests/${TEST_FILE}?channel=test" "${TEST_NAME}.0.log" "update from test channel installed"
+ start_cobalt "file:///tests/${TEST_FILE}?channel=test" "${TEST_NAME}.0.log" "update from test channel was installed"
if [[ $? -ne 0 ]]; then
error "Failed to download and install the test package"
diff --git a/src/starboard/evergreen/testing/tests/verify_qa_channel_update_test.sh b/src/starboard/evergreen/testing/tests/verify_qa_channel_update_test.sh
index 1d7e1c9..0bf6f36 100755
--- a/src/starboard/evergreen/testing/tests/verify_qa_channel_update_test.sh
+++ b/src/starboard/evergreen/testing/tests/verify_qa_channel_update_test.sh
@@ -25,7 +25,7 @@
function run_test() {
clear_storage
- start_cobalt "file:///tests/${TEST_FILE}?channel=test" "${TEST_NAME}.0.log" "update from test channel installed"
+ start_cobalt "file:///tests/${TEST_FILE}?channel=test" "${TEST_NAME}.0.log" "update from test channel was installed"
if [[ $? -ne 0 ]]; then
error "Failed to download and install the test package"
diff --git a/src/starboard/linux/shared/configuration_constants.cc b/src/starboard/linux/shared/configuration_constants.cc
index e3ad2c7..4311059 100644
--- a/src/starboard/linux/shared/configuration_constants.cc
+++ b/src/starboard/linux/shared/configuration_constants.cc
@@ -84,20 +84,6 @@
// video.
const uint32_t kSbMediaMaxVideoBitrateInBitsPerSecond = 200 * 1024 * 1024;
-// Specify the number of video frames to be cached during playback. A large
-// value leads to more stable fps but also causes the app to use more memory.
-const uint32_t kSbMediaMaximumVideoFrames = 12;
-
-// The encoded video frames are compressed in different ways, their decoding
-// time can vary a lot. Occasionally a single frame can take longer time to
-// decode than the average time per frame. The player has to cache some frames
-// to account for such inconsistency. The number of frames being cached are
-// controlled by the following two macros.
-//
-// Specify the number of video frames to be cached before the playback starts.
-// Note that set this value too large may increase the playback start delay.
-const uint32_t kSbMediaMaximumVideoPrerollFrames = 4;
-
// Specifies how video frame buffers must be aligned on this platform.
const uint32_t kSbMediaVideoFrameAlignment = 256;
diff --git a/src/starboard/linux/shared/configuration_public.h b/src/starboard/linux/shared/configuration_public.h
index 1990c44..0e847e4 100644
--- a/src/starboard/linux/shared/configuration_public.h
+++ b/src/starboard/linux/shared/configuration_public.h
@@ -199,6 +199,20 @@
// --- Media Configuration ---------------------------------------------------
#if SB_API_VERSION < 12
+// Allow ac3 and ec3 support
+#define SB_HAS_AC3_AUDIO 1
+#endif // SB_API_VERSION < 12
+
+#if SB_API_VERSION < 12
+// Specifies whether this platform updates audio frames asynchronously. In such
+// case an extra parameter will be added to |SbAudioSinkConsumeFramesFunc| to
+// indicate the absolute time that the consumed audio frames are reported.
+// Check document for |SbAudioSinkConsumeFramesFunc| in audio_sink.h for more
+// details.
+#define SB_HAS_ASYNC_AUDIO_FRAMES_REPORTING 0
+#endif // SB_API_VERSION < 12
+
+#if SB_API_VERSION < 12
// The maximum audio bitrate the platform can decode. The following value
// equals to 5M bytes per seconds which is more than enough for compressed
// audio.
@@ -219,26 +233,12 @@
#endif // SB_API_VERSION < 12
#if SB_API_VERSION < 12
-// Specifies whether this platform updates audio frames asynchronously. In such
-// case an extra parameter will be added to |SbAudioSinkConsumeFramesFunc| to
-// indicate the absolute time that the consumed audio frames are reported.
-// Check document for |SbAudioSinkConsumeFramesFunc| in audio_sink.h for more
-// details.
-#define SB_HAS_ASYNC_AUDIO_FRAMES_REPORTING 0
-#endif // SB_API_VERSION < 12
-
-#if SB_API_VERSION < 12
// Specifies the stack size for threads created inside media stack. Set to 0 to
// use the default thread stack size. Set to non-zero to explicitly set the
// stack size for media stack threads.
#define SB_MEDIA_THREAD_STACK_SIZE 0U
#endif // SB_API_VERSION < 12
-#if SB_API_VERSION < 12
-// Allow ac3 and ec3 support
-#define SB_HAS_AC3_AUDIO 1
-#endif // SB_API_VERSION < 12
-
// --- Decoder-only Params ---
#if SB_API_VERSION < 12
@@ -253,24 +253,6 @@
#define SB_MEDIA_VIDEO_FRAME_ALIGNMENT 256U
#endif // SB_API_VERSION < 12
-#if SB_API_VERSION < 12
-// The encoded video frames are compressed in different ways, their decoding
-// time can vary a lot. Occasionally a single frame can take longer time to
-// decode than the average time per frame. The player has to cache some frames
-// to account for such inconsistency. The number of frames being cached are
-// controlled by the following two macros.
-//
-// Specify the number of video frames to be cached before the playback starts.
-// Note that set this value too large may increase the playback start delay.
-#define SB_MEDIA_MAXIMUM_VIDEO_PREROLL_FRAMES 4
-#endif // SB_API_VERSION < 12
-
-#if SB_API_VERSION < 12
-// Specify the number of video frames to be cached during playback. A large
-// value leads to more stable fps but also causes the app to use more memory.
-#define SB_MEDIA_MAXIMUM_VIDEO_FRAMES 12
-#endif // SB_API_VERSION < 12
-
// --- Memory Configuration --------------------------------------------------
#if SB_API_VERSION < 12
diff --git a/src/starboard/linux/x64x11/blittergles/sbversion/10/configuration_public.h b/src/starboard/linux/x64x11/blittergles/sbversion/10/configuration_public.h
index 3356def..65a0411 100644
--- a/src/starboard/linux/x64x11/blittergles/sbversion/10/configuration_public.h
+++ b/src/starboard/linux/x64x11/blittergles/sbversion/10/configuration_public.h
@@ -88,11 +88,11 @@
// microphone supported.
#define SB_HAS_MICROPHONE 1
+// Whether the current platform implements the on screen keyboard interface.
+#define SB_HAS_ON_SCREEN_KEYBOARD 0
+
// Whether the current platform has speech synthesis.
#undef SB_HAS_SPEECH_SYNTHESIS
#define SB_HAS_SPEECH_SYNTHESIS 0
-// Whether the current platform implements the on screen keyboard interface.
-#define SB_HAS_ON_SCREEN_KEYBOARD 0
-
#endif // STARBOARD_LINUX_X64X11_BLITTERGLES_SBVERSION_10_CONFIGURATION_PUBLIC_H_
diff --git a/src/starboard/linux/x64x11/blittergles/sbversion/11/configuration_public.h b/src/starboard/linux/x64x11/blittergles/sbversion/11/configuration_public.h
index 6aa1686..733c9d8 100644
--- a/src/starboard/linux/x64x11/blittergles/sbversion/11/configuration_public.h
+++ b/src/starboard/linux/x64x11/blittergles/sbversion/11/configuration_public.h
@@ -84,11 +84,11 @@
// microphone supported.
#define SB_HAS_MICROPHONE 1
+// Whether the current platform implements the on screen keyboard interface.
+#define SB_HAS_ON_SCREEN_KEYBOARD 0
+
// Whether the current platform has speech synthesis.
#undef SB_HAS_SPEECH_SYNTHESIS
#define SB_HAS_SPEECH_SYNTHESIS 0
-// Whether the current platform implements the on screen keyboard interface.
-#define SB_HAS_ON_SCREEN_KEYBOARD 0
-
#endif // STARBOARD_LINUX_X64X11_BLITTERGLES_SBVERSION_11_CONFIGURATION_PUBLIC_H_
diff --git a/src/starboard/linux/x64x11/blittergles/shared/configuration_public.h b/src/starboard/linux/x64x11/blittergles/shared/configuration_public.h
index 7a312fd..5661880 100644
--- a/src/starboard/linux/x64x11/blittergles/shared/configuration_public.h
+++ b/src/starboard/linux/x64x11/blittergles/shared/configuration_public.h
@@ -18,6 +18,8 @@
#ifndef STARBOARD_LINUX_X64X11_BLITTERGLES_SHARED_CONFIGURATION_PUBLIC_H_
#define STARBOARD_LINUX_X64X11_BLITTERGLES_SHARED_CONFIGURATION_PUBLIC_H_
+// --- Graphics Configuration ------------------------------------------------
+
// This configuration supports the blitter API (implemented via GLES).
#undef SB_HAS_BLITTER
#define SB_HAS_BLITTER 1
diff --git a/src/starboard/linux/x64x11/configuration_public.h b/src/starboard/linux/x64x11/configuration_public.h
index 38bcc2e..3802b49 100644
--- a/src/starboard/linux/x64x11/configuration_public.h
+++ b/src/starboard/linux/x64x11/configuration_public.h
@@ -57,14 +57,13 @@
#define SB_HAS_MICROPHONE 1
#endif // SB_API_VERSION < 12
-// Whether the current platform has speech synthesis.
-#undef SB_HAS_SPEECH_SYNTHESIS
-#define SB_HAS_SPEECH_SYNTHESIS 0
-
#if SB_API_VERSION >= 8
// Whether the current platform implements the on screen keyboard interface.
#define SB_HAS_ON_SCREEN_KEYBOARD 0
-
#endif // SB_API_VERSION >= 8
+// Whether the current platform has speech synthesis.
+#undef SB_HAS_SPEECH_SYNTHESIS
+#define SB_HAS_SPEECH_SYNTHESIS 0
+
#endif // STARBOARD_LINUX_X64X11_CONFIGURATION_PUBLIC_H_
diff --git a/src/starboard/linux/x64x11/sbversion/10/configuration_public.h b/src/starboard/linux/x64x11/sbversion/10/configuration_public.h
index 484c00a..8f0475e 100644
--- a/src/starboard/linux/x64x11/sbversion/10/configuration_public.h
+++ b/src/starboard/linux/x64x11/sbversion/10/configuration_public.h
@@ -84,13 +84,13 @@
// microphone supported.
#define SB_HAS_MICROPHONE 1
+// Whether the current platform implements the on screen keyboard interface.
+#define SB_HAS_ON_SCREEN_KEYBOARD 0
+
// Whether the current platform has speech synthesis.
#undef SB_HAS_SPEECH_SYNTHESIS
#define SB_HAS_SPEECH_SYNTHESIS 0
-// Whether the current platform implements the on screen keyboard interface.
-#define SB_HAS_ON_SCREEN_KEYBOARD 0
-
// Whether the current platform has JIT support
#define ENGINE_SUPPORTS_JIT 1
diff --git a/src/starboard/linux/x64x11/sbversion/11/configuration_public.h b/src/starboard/linux/x64x11/sbversion/11/configuration_public.h
index 3513fc5..fc32b78 100644
--- a/src/starboard/linux/x64x11/sbversion/11/configuration_public.h
+++ b/src/starboard/linux/x64x11/sbversion/11/configuration_public.h
@@ -80,11 +80,11 @@
// microphone supported.
#define SB_HAS_MICROPHONE 1
+// Whether the current platform implements the on screen keyboard interface.
+#define SB_HAS_ON_SCREEN_KEYBOARD 0
+
// Whether the current platform has speech synthesis.
#undef SB_HAS_SPEECH_SYNTHESIS
#define SB_HAS_SPEECH_SYNTHESIS 0
-// Whether the current platform implements the on screen keyboard interface.
-#define SB_HAS_ON_SCREEN_KEYBOARD 0
-
#endif // STARBOARD_LINUX_X64X11_SBVERSION_11_CONFIGURATION_PUBLIC_H_
diff --git a/src/starboard/linux/x64x11/sbversion/12/configuration_public.h b/src/starboard/linux/x64x11/sbversion/12/configuration_public.h
index b38e6b0..e9d00ac 100644
--- a/src/starboard/linux/x64x11/sbversion/12/configuration_public.h
+++ b/src/starboard/linux/x64x11/sbversion/12/configuration_public.h
@@ -33,11 +33,11 @@
// Include the Linux configuration that's common between all Desktop Linuxes.
#include "starboard/linux/shared/configuration_public.h"
+// Whether the current platform implements the on screen keyboard interface.
+#define SB_HAS_ON_SCREEN_KEYBOARD 0
+
// Whether the current platform has speech synthesis.
#undef SB_HAS_SPEECH_SYNTHESIS
#define SB_HAS_SPEECH_SYNTHESIS 0
-// Whether the current platform implements the on screen keyboard interface.
-#define SB_HAS_ON_SCREEN_KEYBOARD 0
-
#endif // STARBOARD_LINUX_X64X11_SBVERSION_12_CONFIGURATION_PUBLIC_H_
diff --git a/src/starboard/loader_app/installation_manager.cc b/src/starboard/loader_app/installation_manager.cc
index 9325c94..0401b50 100644
--- a/src/starboard/loader_app/installation_manager.cc
+++ b/src/starboard/loader_app/installation_manager.cc
@@ -574,20 +574,23 @@
bool InstallationManager::SaveInstallationStore() {
ValidatePriorities();
- char buf[IM_MAX_INSTALLATION_STORE_SIZE];
+
if (IM_MAX_INSTALLATION_STORE_SIZE < installation_store_.ByteSize()) {
SB_LOG(ERROR) << "SaveInstallationStore: Data too large"
<< installation_store_.ByteSize();
return false;
}
+ const size_t buf_size = installation_store_.ByteSize();
+ std::vector<char> buf(buf_size, 0);
loader_app::SetPendingRestart(
installation_store_.roll_forward_to_installation() != -1);
- installation_store_.SerializeToArray(buf, installation_store_.ByteSize());
+ installation_store_.SerializeToArray(buf.data(),
+ installation_store_.ByteSize());
#if SB_API_VERSION >= 12
- if (!SbFileAtomicReplace(store_path_.c_str(), buf,
+ if (!SbFileAtomicReplace(store_path_.c_str(), buf.data(),
installation_store_.ByteSize())) {
SB_LOG(ERROR)
<< "SaveInstallationStore: Failed to store installation store: "
diff --git a/src/starboard/nplb/atomic_base_test.cc b/src/starboard/nplb/atomic_base_test.cc
index f5fb925..3128e5a 100644
--- a/src/starboard/nplb/atomic_base_test.cc
+++ b/src/starboard/nplb/atomic_base_test.cc
@@ -68,7 +68,8 @@
SbThread thread_;
- SB_DISALLOW_COPY_AND_ASSIGN(TestThread);
+ TestThread(const TestThread&) = delete;
+ void operator=(const TestThread&) = delete;
};
///////////////////////////////////////////////////////////////////////////////
diff --git a/src/starboard/nplb/nplb_evergreen_compat_tests/sabi_test.cc b/src/starboard/nplb/nplb_evergreen_compat_tests/sabi_test.cc
index 60b6d6e..ac659ac 100644
--- a/src/starboard/nplb/nplb_evergreen_compat_tests/sabi_test.cc
+++ b/src/starboard/nplb/nplb_evergreen_compat_tests/sabi_test.cc
@@ -155,6 +155,12 @@
};
TEST_F(SabiTest, VerifySABI) {
+ SB_LOG(INFO) << "Using SB_API_VERSION=" << SB_API_VERSION;
+ SB_LOG(INFO) << "Using SABI=" << SB_SABI_JSON_ID;
+
+ ASSERT_LT(SB_API_VERSION, SB_EXPERIMENTAL_API_VERSION)
+ << "Evergreen should use SB_API_VERSION < SB_EXPERIMENTAL_API_VERSION";
+
std::set<std::string> sabi_set;
sabi_set.insert(kSabiJsonIdArmHardfp);
sabi_set.insert(kSabiJsonIdArmSoftfp);
diff --git a/src/starboard/nplb/system_get_stack_test.cc b/src/starboard/nplb/system_get_stack_test.cc
index 89c273a..9b0f3db 100644
--- a/src/starboard/nplb/system_get_stack_test.cc
+++ b/src/starboard/nplb/system_get_stack_test.cc
@@ -21,12 +21,14 @@
namespace {
SB_C_NOINLINE int GetStackWithAnExtraFrame(void** out_stack, int stack_size) {
- // This EXPECT_NE is just enough to avoid inlining with optimizations on.
- // This may not be enough on other platforms, so we'll have to keep an eye on
- // it.
+ // These EXPECT_NE and EXPECT_LT should be enough to make function complicated
+ // and avoid inlining with optimizations on some platforms. But we'll have to
+ // keep an eye on it as this may not be enough on some other platforms.
void** const kNullVpp = NULL;
EXPECT_NE(kNullVpp, out_stack);
- return SbSystemGetStack(out_stack, stack_size);
+ int ret = SbSystemGetStack(out_stack, stack_size);
+ EXPECT_LT(1, ret);
+ return ret;
}
SB_C_NOINLINE void WowThatsADeepStack() {
diff --git a/src/starboard/nplb/thread_helpers.h b/src/starboard/nplb/thread_helpers.h
index a646aa3..c3851f9 100644
--- a/src/starboard/nplb/thread_helpers.h
+++ b/src/starboard/nplb/thread_helpers.h
@@ -160,14 +160,11 @@
void Start() {
SbThreadEntryPoint entry_point = ThreadEntryPoint;
- thread_ = SbThreadCreate(
- 0, // default stack_size.
- kSbThreadNoPriority, // default priority.
- kSbThreadNoAffinity, // default affinity.
- true, // joinable.
- "AbstractTestThread",
- entry_point,
- this);
+ thread_ = SbThreadCreate(0, // default stack_size.
+ kSbThreadNoPriority, // default priority.
+ kSbThreadNoAffinity, // default affinity.
+ true, // joinable.
+ "AbstractTestThread", entry_point, this);
if (kSbThreadInvalid == thread_) {
ADD_FAILURE_AT(__FILE__, __LINE__) << "Invalid thread.";
@@ -192,7 +189,8 @@
SbThread thread_;
- SB_DISALLOW_COPY_AND_ASSIGN(AbstractTestThread);
+ AbstractTestThread(const AbstractTestThread&) = delete;
+ void operator=(const AbstractTestThread&) = delete;
};
} // namespace nplb
diff --git a/src/starboard/raspi/2/sbversion/12/configuration_public.h b/src/starboard/raspi/2/sbversion/12/configuration_public.h
index c91229a..a1a55da 100644
--- a/src/starboard/raspi/2/sbversion/12/configuration_public.h
+++ b/src/starboard/raspi/2/sbversion/12/configuration_public.h
@@ -131,13 +131,6 @@
// required for platforms that want to JIT.
#define SB_CAN_MAP_EXECUTABLE_MEMORY 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
-
// --- Network Configuration -------------------------------------------------
// Specifies whether this platform supports IPV6.
@@ -158,4 +151,13 @@
#error "RasPi builds need a GCC-like compiler (for the moment)."
#endif
+// --- Platform Specific Quirks ----------------------------------------------
+
+// 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
+
#endif // STARBOARD_RASPI_2_SBVERSION_12_CONFIGURATION_PUBLIC_H_
diff --git a/src/starboard/raspi/shared/configuration_constants.cc b/src/starboard/raspi/shared/configuration_constants.cc
index 6816391..f733b23 100644
--- a/src/starboard/raspi/shared/configuration_constants.cc
+++ b/src/starboard/raspi/shared/configuration_constants.cc
@@ -84,20 +84,6 @@
// video.
const uint32_t kSbMediaMaxVideoBitrateInBitsPerSecond = 200 * 1024 * 1024;
-// Specify the number of video frames to be cached during playback. A large
-// value leads to more stable fps but also causes the app to use more memory.
-const uint32_t kSbMediaMaximumVideoFrames = 12;
-
-// The encoded video frames are compressed in different ways, their decoding
-// time can vary a lot. Occasionally a single frame can take longer time to
-// decode than the average time per frame. The player has to cache some frames
-// to account for such inconsistency. The number of frames being cached are
-// controlled by the following two macros.
-//
-// Specify the number of video frames to be cached before the playback starts.
-// Note that set this value too large may increase the playback start delay.
-const uint32_t kSbMediaMaximumVideoPrerollFrames = 4;
-
// Specifies how video frame buffers must be aligned on this platform.
const uint32_t kSbMediaVideoFrameAlignment = 256;
diff --git a/src/starboard/raspi/shared/configuration_public.h b/src/starboard/raspi/shared/configuration_public.h
index 05988f6..8c437cf 100644
--- a/src/starboard/raspi/shared/configuration_public.h
+++ b/src/starboard/raspi/shared/configuration_public.h
@@ -146,13 +146,6 @@
// required for platforms that want to JIT.
#define SB_CAN_MAP_EXECUTABLE_MEMORY 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
-
// --- Network Configuration -------------------------------------------------
// Specifies whether this platform supports IPV6.
@@ -179,4 +172,13 @@
#error "RasPi builds need a GCC-like compiler (for the moment)."
#endif
+// --- Platform Specific Quirks ----------------------------------------------
+
+// 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
+
#endif // STARBOARD_RASPI_SHARED_CONFIGURATION_PUBLIC_H_
diff --git a/src/starboard/raspi/shared/dispmanx_util.cc b/src/starboard/raspi/shared/dispmanx_util.cc
index 906cfb0..076c1a5 100644
--- a/src/starboard/raspi/shared/dispmanx_util.cc
+++ b/src/starboard/raspi/shared/dispmanx_util.cc
@@ -49,7 +49,8 @@
private:
DISPMANX_UPDATE_HANDLE_T handle_;
- SB_DISALLOW_COPY_AND_ASSIGN(DispmanxAutoUpdate);
+ DispmanxAutoUpdate(const DispmanxAutoUpdate&) = delete;
+ void operator=(const DispmanxAutoUpdate&) = delete;
};
} // namespace
diff --git a/src/starboard/raspi/shared/dispmanx_util.h b/src/starboard/raspi/shared/dispmanx_util.h
index 4556323..5646d24 100644
--- a/src/starboard/raspi/shared/dispmanx_util.h
+++ b/src/starboard/raspi/shared/dispmanx_util.h
@@ -56,7 +56,8 @@
private:
DISPMANX_DISPLAY_HANDLE_T handle_;
- SB_DISALLOW_COPY_AND_ASSIGN(DispmanxDisplay);
+ DispmanxDisplay(const DispmanxDisplay&) = delete;
+ void operator=(const DispmanxDisplay&) = delete;
};
class DispmanxResource {
@@ -90,7 +91,8 @@
uint32_t visible_width_;
uint32_t visible_height_;
- SB_DISALLOW_COPY_AND_ASSIGN(DispmanxResource);
+ DispmanxResource(const DispmanxResource&) = delete;
+ void operator=(const DispmanxResource&) = delete;
};
class DispmanxYUV420Resource : public DispmanxResource {
@@ -140,7 +142,8 @@
private:
DISPMANX_ELEMENT_HANDLE_T handle_;
- SB_DISALLOW_COPY_AND_ASSIGN(DispmanxElement);
+ DispmanxElement(const DispmanxElement&) = delete;
+ void operator=(const DispmanxElement&) = delete;
};
class DispmanxVideoFrame
@@ -183,7 +186,8 @@
// console does not show through.
DispmanxRGB565Resource black_frame_;
- SB_DISALLOW_COPY_AND_ASSIGN(DispmanxVideoRenderer);
+ DispmanxVideoRenderer(const DispmanxVideoRenderer&) = delete;
+ void operator=(const DispmanxVideoRenderer&) = delete;
};
} // namespace shared
diff --git a/src/starboard/shared/ffmpeg/ffmpeg_video_decoder_impl.cc b/src/starboard/shared/ffmpeg/ffmpeg_video_decoder_impl.cc
index cba4c7e..b786f9c 100644
--- a/src/starboard/shared/ffmpeg/ffmpeg_video_decoder_impl.cc
+++ b/src/starboard/shared/ffmpeg/ffmpeg_video_decoder_impl.cc
@@ -46,7 +46,7 @@
#if LIBAVUTIL_VERSION_INT >= LIBAVUTIL_VERSION_52_8
void ReleaseBuffer(void* opaque, uint8_t* data) {
- SbMemoryDeallocate(data);
+ SbMemoryDeallocateAligned(data);
}
int AllocateBufferCallback(AVCodecContext* codec_context,
@@ -66,7 +66,7 @@
}
void ReleaseBuffer(AVCodecContext*, AVFrame* frame) {
- SbMemoryDeallocate(frame->opaque);
+ SbMemoryDeallocateAligned(frame->opaque);
frame->opaque = NULL;
// The FFmpeg API expects us to zero the data pointers in this callback.
@@ -275,8 +275,9 @@
int codec_aligned_width = av_frame_->width;
int codec_aligned_height = av_frame_->height;
int codec_linesize_align[AV_NUM_DATA_POINTERS];
- ffmpeg_->avcodec_align_dimensions2(codec_context_,
- &codec_aligned_width, &codec_aligned_height, codec_linesize_align);
+ ffmpeg_->avcodec_align_dimensions2(codec_context_, &codec_aligned_width,
+ &codec_aligned_height,
+ codec_linesize_align);
int pitch = AlignUp(av_frame_->width, codec_linesize_align[0] * 2);
@@ -425,8 +426,9 @@
int codec_aligned_width = codec_context->width;
int codec_aligned_height = codec_context->height;
int codec_linesize_align[AV_NUM_DATA_POINTERS];
- ffmpeg_->avcodec_align_dimensions2(codec_context,
- &codec_aligned_width, &codec_aligned_height, codec_linesize_align);
+ ffmpeg_->avcodec_align_dimensions2(codec_context, &codec_aligned_width,
+ &codec_aligned_height,
+ codec_linesize_align);
// Align to linesize alignment * 2 as we will divide y_stride by 2 for
// u and v planes.
@@ -478,8 +480,9 @@
int codec_aligned_width = codec_context->width;
int codec_aligned_height = codec_context->height;
int codec_linesize_align[AV_NUM_DATA_POINTERS];
- ffmpeg_->avcodec_align_dimensions2(codec_context,
- &codec_aligned_width, &codec_aligned_height, codec_linesize_align);
+ ffmpeg_->avcodec_align_dimensions2(codec_context, &codec_aligned_width,
+ &codec_aligned_height,
+ codec_linesize_align);
// Align to linesize alignment * 2 as we will divide y_stride by 2 for
// u and v planes.
diff --git a/src/starboard/shared/libdav1d/dav1d_video_decoder.cc b/src/starboard/shared/libdav1d/dav1d_video_decoder.cc
index 384b38a..3526b0a 100644
--- a/src/starboard/shared/libdav1d/dav1d_video_decoder.cc
+++ b/src/starboard/shared/libdav1d/dav1d_video_decoder.cc
@@ -188,7 +188,7 @@
SB_DCHECK(picture->data[0] < picture->data[1]);
SB_DCHECK(picture->data[1] < picture->data[2]);
- SbMemoryDeallocate(picture->data[0]);
+ SbMemoryDeallocateAligned(picture->data[0]);
for (int i = 0; i < 3; ++i) {
picture->data[i] = NULL;
}
diff --git a/src/starboard/shared/starboard/application.cc b/src/starboard/shared/starboard/application.cc
index 406e4aa..50f622a 100644
--- a/src/starboard/shared/starboard/application.cc
+++ b/src/starboard/shared/starboard/application.cc
@@ -316,6 +316,7 @@
case kStateStopped:
return true;
case kStateFrozen:
+ OnResume();
Inject(new Event(kSbEventTypeUnfreeze, NULL, NULL));
Inject(scoped_event.release());
return true;
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 bffc40a..c1cf847 100644
--- a/src/starboard/shared/starboard/audio_sink/audio_sink_internal.h
+++ b/src/starboard/shared/starboard/audio_sink/audio_sink_internal.h
@@ -27,6 +27,7 @@
// When |capability_changed| is true, it hints that the error is caused by a
// a transisent capability on the platform. The app should retry playback to
// recover from the error.
+ // TODO: Allow to pass an error message.
typedef void (*ErrorFunc)(bool capability_changed, void* context);
#endif // SB_API_VERSION >= 12
diff --git a/src/starboard/shared/starboard/configuration_constants_compatibility_defines.h b/src/starboard/shared/starboard/configuration_constants_compatibility_defines.h
index 0952566..1aff514 100644
--- a/src/starboard/shared/starboard/configuration_constants_compatibility_defines.h
+++ b/src/starboard/shared/starboard/configuration_constants_compatibility_defines.h
@@ -61,10 +61,6 @@
#define kSbMediaMaxVideoBitrateInBitsPerSecond \
SB_MEDIA_MAX_VIDEO_BITRATE_IN_BITS_PER_SECOND
-#define kSbMediaMaximumVideoFrames SB_MEDIA_MAXIMUM_VIDEO_FRAMES
-
-#define kSbMediaMaximumVideoPrerollFrames SB_MEDIA_MAXIMUM_VIDEO_PREROLL_FRAMES
-
#define kSbMediaVideoFrameAlignment SB_MEDIA_VIDEO_FRAME_ALIGNMENT
#define kSbMemoryLogPath SB_MEMORY_LOG_PATH
diff --git a/src/starboard/shared/starboard/media/media_util.cc b/src/starboard/shared/starboard/media/media_util.cc
index 7dab6c0..8005cd8 100644
--- a/src/starboard/shared/starboard/media/media_util.cc
+++ b/src/starboard/shared/starboard/media/media_util.cc
@@ -627,6 +627,20 @@
return "Invalid";
}
+#if SB_API_VERSION >= 11
+bool IsAudioSampleInfoSubstantiallyDifferent(
+ const SbMediaAudioSampleInfo& left,
+ const SbMediaAudioSampleInfo& right) {
+ return left.codec != right.codec ||
+ left.samples_per_second != right.samples_per_second ||
+ left.number_of_channels != right.number_of_channels ||
+ left.audio_specific_config_size != right.audio_specific_config_size ||
+ SbMemoryCompare(left.audio_specific_config,
+ right.audio_specific_config,
+ left.audio_specific_config_size) != 0;
+}
+#endif // SB_API_VERSION < 11
+
} // namespace media
} // namespace starboard
} // namespace shared
diff --git a/src/starboard/shared/starboard/media/media_util.h b/src/starboard/shared/starboard/media/media_util.h
index 72edc89..15a9742 100644
--- a/src/starboard/shared/starboard/media/media_util.h
+++ b/src/starboard/shared/starboard/media/media_util.h
@@ -104,6 +104,14 @@
const char* GetMatrixIdName(SbMediaMatrixId matrix_id);
const char* GetRangeIdName(SbMediaRangeId range_id);
+#if SB_API_VERSION >= 11
+// When this function returns true, usually indicates that the two sample info
+// cannot be processed by the same audio decoder.
+bool IsAudioSampleInfoSubstantiallyDifferent(
+ const SbMediaAudioSampleInfo& left,
+ const SbMediaAudioSampleInfo& right);
+#endif // SB_API_VERSION < 11
+
} // namespace media
} // namespace starboard
} // namespace shared
diff --git a/src/starboard/shared/starboard/net_log.cc b/src/starboard/shared/starboard/net_log.cc
index c63c27b..24f733a 100644
--- a/src/starboard/shared/starboard/net_log.cc
+++ b/src/starboard/shared/starboard/net_log.cc
@@ -66,20 +66,16 @@
class FunctionThread : public Thread {
public:
- static scoped_ptr<Thread> Create(
- const std::string& thread_name,
- RunFunction run_function) {
+ static scoped_ptr<Thread> Create(const std::string& thread_name,
+ RunFunction run_function) {
scoped_ptr<Thread> out(new FunctionThread(thread_name, run_function));
return out.Pass();
}
FunctionThread(const std::string& name, RunFunction run_function)
- : Thread(name), run_function_(run_function) {
- }
+ : Thread(name), run_function_(run_function) {}
- void Run() override {
- run_function_(join_sema());
- }
+ void Run() override { run_function_(join_sema()); }
private:
RunFunction run_function_;
@@ -87,17 +83,22 @@
std::string ToString(SbSocketError error) {
switch (error) {
- case kSbSocketOk: { return "kSbSocketOk"; }
- case kSbSocketPending: { return "kSbSocketErrorConnectionReset"; }
- case kSbSocketErrorFailed: { return "kSbSocketErrorFailed"; }
+ case kSbSocketOk: {
+ return "kSbSocketOk";
+ }
+ case kSbSocketPending: {
+ return "kSbSocketErrorConnectionReset";
+ }
+ case kSbSocketErrorFailed: {
+ return "kSbSocketErrorFailed";
+ }
-#if SB_HAS(SOCKET_ERROR_CONNECTION_RESET_SUPPORT) || \
- SB_API_VERSION >= 9
+#if SB_HAS(SOCKET_ERROR_CONNECTION_RESET_SUPPORT) || SB_API_VERSION >= 9
case kSbSocketErrorConnectionReset: {
return "kSbSocketErrorConnectionReset";
}
#endif // SB_HAS(SOCKET_ERROR_CONNECTION_RESET_SUPPORT) ||
- // SB_API_VERSION >= 9
+ // SB_API_VERSION >= 9
}
SB_NOTREACHED() << "Unexpected case " << error;
std::stringstream ss;
@@ -167,10 +168,7 @@
}
};
- SbSocketWaiterAdd(waiter,
- sock,
- NULL,
- &F::WakeUp,
+ SbSocketWaiterAdd(waiter, sock, NULL, &F::WakeUp,
kSbSocketWaiterInterestWrite,
false); // false means one shot.
@@ -180,8 +178,7 @@
}
bool IsConnectionReset(SbSocketError err) {
-#if SB_HAS(SOCKET_ERROR_CONNECTION_RESET_SUPPORT) || \
- SB_API_VERSION >= 9
+#if SB_HAS(SOCKET_ERROR_CONNECTION_RESET_SUPPORT) || SB_API_VERSION >= 9
return err == kSbSocketErrorConnectionReset;
#else
return false;
@@ -250,9 +247,7 @@
void PrependData(const std::string& curr_write_block) {
ScopedLock lock_log(log_mutex_);
- log_.insert(log_.begin(),
- curr_write_block.begin(),
- curr_write_block.end());
+ log_.insert(log_.begin(), curr_write_block.begin(), curr_write_block.end());
}
int max_memory_buffer_size_;
@@ -270,16 +265,13 @@
typedef std::function<void(scoped_ptr<Socket>)> Callback;
SocketListener(Socket* listen_socket, Callback cb)
- : listen_socket_(listen_socket),
- callback_(cb) {
+ : listen_socket_(listen_socket), callback_(cb) {
auto run_cb = [this](Semaphore* sema) { this->Run(sema); };
thread_ = FunctionThread::Create("NetLogSocketListener", run_cb);
thread_->Start();
}
- ~SocketListener() {
- thread_->Join();
- }
+ ~SocketListener() { thread_->Join(); }
private:
void Run(Semaphore* joined_sema) {
@@ -301,15 +293,16 @@
class NetLogServer {
public:
static NetLogServer* Instance();
- NetLogServer() : buffered_socket_writer_(NET_LOG_MAX_IN_MEMORY_BUFFER,
- NET_LOG_SOCKET_SEND_SIZE) {
+ NetLogServer()
+ : buffered_socket_writer_(NET_LOG_MAX_IN_MEMORY_BUFFER,
+ NET_LOG_SOCKET_SEND_SIZE) {
ScopedLock lock(socket_mutex_);
listen_socket_ = CreateListenSocket();
ListenForClient();
writer_thread_ = FunctionThread::Create(
- "NetLogSocketWriter",
- [this](Semaphore* sema) { this->WriterTask(sema); });
+ "NetLogSocketWriter",
+ [this](Semaphore* sema) { this->WriterTask(sema); });
writer_thread_->Start();
}
@@ -319,9 +312,8 @@
}
void ListenForClient() {
- SocketListener::Callback cb = std::bind(&NetLogServer::OnClientConnect,
- this,
- std::placeholders::_1);
+ SocketListener::Callback cb =
+ std::bind(&NetLogServer::OnClientConnect, this, std::placeholders::_1);
socket_listener_.reset();
socket_listener_.reset(new SocketListener(listen_socket_.get(), cb));
}
@@ -413,9 +405,12 @@
void* ptr = SbThreadGetLocalValue(slot_);
return ptr != nullptr;
}
+
private:
SbThreadLocalKey slot_;
- SB_DISALLOW_COPY_AND_ASSIGN(ThreadLocalBoolean);
+
+ ThreadLocalBoolean(const ThreadLocalBoolean&) = delete;
+ void operator=(const ThreadLocalBoolean&) = delete;
};
SB_ONCE_INITIALIZE_FUNCTION(NetLogServer, NetLogServer::Instance);
@@ -430,13 +425,10 @@
tlb_->Set(true);
}
- ~ScopeGuard() {
- tlb_->Set(disabled_);
- }
+ ~ScopeGuard() { tlb_->Set(disabled_); }
- bool IsEnabled() {
- return !disabled_;
- }
+ bool IsEnabled() { return !disabled_; }
+
private:
bool disabled_;
ThreadLocalBoolean* tlb_;
@@ -450,9 +442,9 @@
#if !SB_LOGGING_IS_OFFICIAL_BUILD
ScopeGuard guard;
if (guard.IsEnabled()) {
- SbTimeMonotonic expire_time = (timeout >= 0) && (timeout < kSbTimeMax)?
- SbTimeGetMonotonicNow() + timeout :
- kSbTimeMax;
+ SbTimeMonotonic expire_time = (timeout >= 0) && (timeout < kSbTimeMax)
+ ? SbTimeGetMonotonicNow() + timeout
+ : kSbTimeMax;
while (true) {
if (NetLogServer::Instance()->HasClientConnected()) {
break;
diff --git a/src/starboard/shared/starboard/player/decoded_audio_internal.cc b/src/starboard/shared/starboard/player/decoded_audio_internal.cc
index 1e21a40..aca60f5 100644
--- a/src/starboard/shared/starboard/player/decoded_audio_internal.cc
+++ b/src/starboard/shared/starboard/player/decoded_audio_internal.cc
@@ -81,10 +81,11 @@
if (samples_per_second == 0 || frames_to_remove < 0 ||
frames_to_remove >= frames()) {
- SB_LOG(WARNING) << "AdjustForSeekTime failed for seeking_to_time at "
- << seeking_to_time << " for samples_per_second "
- << samples_per_second << ", and there are " << frames()
- << " frames in the DecodedAudio object.";
+ SB_LOG(WARNING) << "AdjustForSeekTime failed for seeking_to_time: "
+ << seeking_to_time
+ << ", samples_per_second: " << samples_per_second
+ << ", timestamp: " << timestamp() << ", and there are "
+ << frames() << " frames in the DecodedAudio object.";
return;
}
diff --git a/src/starboard/shared/starboard/player/decoded_audio_internal.h b/src/starboard/shared/starboard/player/decoded_audio_internal.h
index 0ac7681..521bf95 100644
--- a/src/starboard/shared/starboard/player/decoded_audio_internal.h
+++ b/src/starboard/shared/starboard/player/decoded_audio_internal.h
@@ -73,7 +73,8 @@
scoped_array<uint8_t> buffer_;
size_t size_;
- SB_DISALLOW_COPY_AND_ASSIGN(DecodedAudio);
+ DecodedAudio(const DecodedAudio&) = delete;
+ void operator=(const DecodedAudio&) = delete;
};
} // namespace player
diff --git a/src/starboard/shared/starboard/player/filter/adaptive_audio_decoder_internal.cc b/src/starboard/shared/starboard/player/filter/adaptive_audio_decoder_internal.cc
index ae3b448..8eba0ca 100644
--- a/src/starboard/shared/starboard/player/filter/adaptive_audio_decoder_internal.cc
+++ b/src/starboard/shared/starboard/player/filter/adaptive_audio_decoder_internal.cc
@@ -17,6 +17,7 @@
#include "starboard/audio_sink.h"
#include "starboard/common/log.h"
#include "starboard/common/reset_and_return.h"
+#include "starboard/shared/starboard/media/media_util.h"
#include "starboard/shared/starboard/player/decoded_audio_internal.h"
namespace starboard {
@@ -34,29 +35,6 @@
kDefaultOutputSamplesPerSecond);
}
-bool IsResetDecoderNecessary(const SbMediaAudioSampleInfo& current_info,
- const SbMediaAudioSampleInfo& new_info) {
- if (current_info.codec != new_info.codec) {
- return true;
- }
- if (current_info.samples_per_second != new_info.samples_per_second) {
- return true;
- }
- if (current_info.number_of_channels != new_info.number_of_channels) {
- return true;
- }
- if (current_info.audio_specific_config_size !=
- new_info.audio_specific_config_size) {
- return true;
- }
- if (SbMemoryCompare(current_info.audio_specific_config,
- new_info.audio_specific_config,
- current_info.audio_specific_config_size) != 0) {
- return true;
- }
- return false;
-}
-
AdaptiveAudioDecoder::AdaptiveAudioDecoder(
const SbMediaAudioSampleInfo& audio_sample_info,
SbDrmSystem drm_system,
@@ -107,8 +85,8 @@
}
return;
}
- if (IsResetDecoderNecessary(input_audio_sample_info_,
- input_buffer->audio_sample_info())) {
+ if (starboard::media::IsAudioSampleInfoSubstantiallyDifferent(
+ input_audio_sample_info_, input_buffer->audio_sample_info())) {
flushing_ = true;
pending_input_buffer_ = input_buffer;
pending_consumed_cb_ = consumed_cb;
diff --git a/src/starboard/shared/starboard/player/filter/audio_time_stretcher.h b/src/starboard/shared/starboard/player/filter/audio_time_stretcher.h
index 3170a01..e0bbe8b 100644
--- a/src/starboard/shared/starboard/player/filter/audio_time_stretcher.h
+++ b/src/starboard/shared/starboard/player/filter/audio_time_stretcher.h
@@ -218,7 +218,8 @@
int initial_capacity_;
int max_capacity_;
- SB_DISALLOW_COPY_AND_ASSIGN(AudioTimeStretcher);
+ AudioTimeStretcher(const AudioTimeStretcher&) = delete;
+ void operator=(const AudioTimeStretcher&) = delete;
};
} // namespace filter
diff --git a/src/starboard/shared/starboard/player/filter/decoded_audio_queue.h b/src/starboard/shared/starboard/player/filter/decoded_audio_queue.h
index 83ca887..abf2c7b 100644
--- a/src/starboard/shared/starboard/player/filter/decoded_audio_queue.h
+++ b/src/starboard/shared/starboard/player/filter/decoded_audio_queue.h
@@ -97,7 +97,8 @@
// Number of frames available to be read in the buffer.
int frames_;
- SB_DISALLOW_COPY_AND_ASSIGN(DecodedAudioQueue);
+ DecodedAudioQueue(const DecodedAudioQueue&) = delete;
+ void operator=(const DecodedAudioQueue&) = delete;
};
} // namespace filter
diff --git a/src/starboard/shared/starboard/player/filter/interleaved_sinc_resampler.h b/src/starboard/shared/starboard/player/filter/interleaved_sinc_resampler.h
index b7f2b15..be29e2d 100644
--- a/src/starboard/shared/starboard/player/filter/interleaved_sinc_resampler.h
+++ b/src/starboard/shared/starboard/player/filter/interleaved_sinc_resampler.h
@@ -86,7 +86,8 @@
scoped_array<float> data_;
int frames_ = 0;
- SB_DISALLOW_COPY_AND_ASSIGN(Buffer);
+ Buffer(const Buffer&) = delete;
+ void operator=(const Buffer&) = delete;
};
// The kernel size can be adjusted for quality (higher is better) at the
@@ -164,7 +165,8 @@
float* r4_;
float* r5_;
- SB_DISALLOW_COPY_AND_ASSIGN(InterleavedSincResampler);
+ InterleavedSincResampler(const InterleavedSincResampler&) = delete;
+ void operator=(const InterleavedSincResampler&) = delete;
};
} // namespace filter
diff --git a/src/starboard/shared/starboard/player/filter/player_components.h b/src/starboard/shared/starboard/player/filter/player_components.h
index e4c0eef..543ca34 100644
--- a/src/starboard/shared/starboard/player/filter/player_components.h
+++ b/src/starboard/shared/starboard/player/filter/player_components.h
@@ -113,12 +113,8 @@
}
#endif // SB_HAS(PLAYER_CREATION_AND_OUTPUT_MODE_QUERY_IMPROVEMENT)
- SbPlayer player() const {
- return player_;
- }
- SbPlayerOutputMode output_mode() const {
- return output_mode_;
- }
+ SbPlayer player() const { return player_; }
+ SbPlayerOutputMode output_mode() const { return output_mode_; }
SbDecodeTargetGraphicsContextProvider*
decode_target_graphics_context_provider() const {
SB_DCHECK(video_codec_ != kSbMediaVideoCodecNone);
@@ -203,7 +199,8 @@
int* min_frames_per_append) const;
private:
- SB_DISALLOW_COPY_AND_ASSIGN(Factory);
+ Factory(const Factory&) = delete;
+ void operator=(const Factory&) = delete;
};
PlayerComponents() = default;
@@ -214,7 +211,8 @@
virtual VideoRenderer* GetVideoRenderer() = 0;
private:
- SB_DISALLOW_COPY_AND_ASSIGN(PlayerComponents);
+ PlayerComponents(const PlayerComponents&) = delete;
+ void operator=(const PlayerComponents&) = delete;
};
} // namespace filter
diff --git a/src/starboard/shared/starboard/player/filter/stub_player_components_factory.h b/src/starboard/shared/starboard/player/filter/stub_player_components_factory.h
index 1a9f49e..5753f27 100644
--- a/src/starboard/shared/starboard/player/filter/stub_player_components_factory.h
+++ b/src/starboard/shared/starboard/player/filter/stub_player_components_factory.h
@@ -54,7 +54,8 @@
private:
StubPlayerComponentsFactory() {}
- SB_DISALLOW_COPY_AND_ASSIGN(StubPlayerComponentsFactory);
+ StubPlayerComponentsFactory(const StubPlayerComponentsFactory&) = delete;
+ void operator=(const StubPlayerComponentsFactory&) = delete;
};
} // namespace filter
diff --git a/src/starboard/shared/starboard/player/filter/video_frame_internal.h b/src/starboard/shared/starboard/player/filter/video_frame_internal.h
index b3705ef..08084eb 100644
--- a/src/starboard/shared/starboard/player/filter/video_frame_internal.h
+++ b/src/starboard/shared/starboard/player/filter/video_frame_internal.h
@@ -49,7 +49,8 @@
private:
SbTime timestamp_;
- SB_DISALLOW_COPY_AND_ASSIGN(VideoFrame);
+ VideoFrame(const VideoFrame&) = delete;
+ void operator=(const VideoFrame&) = delete;
};
} // namespace filter
diff --git a/src/starboard/shared/starboard/player/input_buffer_internal.h b/src/starboard/shared/starboard/player/input_buffer_internal.h
index 718c5bb..efca7f7 100644
--- a/src/starboard/shared/starboard/player/input_buffer_internal.h
+++ b/src/starboard/shared/starboard/player/input_buffer_internal.h
@@ -93,7 +93,8 @@
std::vector<SbDrmSubSampleMapping> subsamples_;
std::vector<uint8_t> flattened_data_;
- SB_DISALLOW_COPY_AND_ASSIGN(InputBuffer);
+ InputBuffer(const InputBuffer&) = delete;
+ void operator=(const InputBuffer&) = delete;
};
} // namespace player
diff --git a/src/starboard/shared/starboard/player/player.gyp b/src/starboard/shared/starboard/player/player.gyp
index 2f8e366..8e3c9eb 100644
--- a/src/starboard/shared/starboard/player/player.gyp
+++ b/src/starboard/shared/starboard/player/player.gyp
@@ -13,7 +13,6 @@
# limitations under the License.
{
-
'targets': [
{
'target_name': 'video_dmp',
@@ -38,24 +37,33 @@
'target_name': 'player_copy_test_data',
'type': 'none',
'variables': {
- 'content_test_input_files': ['<!@pymod_do_main(starboard.build.gyp_functions file_glob_sub <(DEPTH)/starboard/shared/starboard/player/testdata *.dmp.sha1 dmp.sha1 dmp)'],
+ 'content_test_input_files': [
+ '<!@pymod_do_main(starboard.build.gyp_functions file_glob_sub <(DEPTH)/starboard/shared/starboard/player/testdata *.dmp.sha1 dmp.sha1 dmp)'
+ ],
'content_test_output_subdir': 'starboard/shared/starboard/player/testdata',
- 'download_from_google_storage_path': ['<!@pymod_do_main(starboard.build.gyp_functions find_program download_from_google_storage)'],
},
'actions' : [
{
- # This action requires depot_tools to be in path
- # (https://cobalt.googlesource.com/depot_tools).
+ 'variables': {
+ 'sha_dir': '<(DEPTH)/starboard/shared/starboard/player/testdata',
+ # GYP will remove an argument to an action that looks like a duplicate, so
+ # we change it semantically here.
+ 'out_dir': '<(DEPTH)/starboard/../starboard/shared/starboard/player/testdata',
+ },
'action_name': 'player_download_test_data',
- 'action': [ '<(download_from_google_storage_path)',
- '--no_resume',
- '--no_auth',
- '--num_threads', '8',
- '--bucket', 'cobalt-static-storage',
- '-d', '<(DEPTH)/starboard/shared/starboard/player/testdata',
+ 'action': [
+ 'python',
+ '<(DEPTH)/tools/download_from_gcs.py',
+ '--bucket', 'cobalt-static-storage',
+ '--sha1', '<(sha_dir)',
+ '--output', '<(out_dir)',
],
- 'inputs': [],
- 'outputs': ['<!@pymod_do_main(starboard.build.gyp_functions file_glob_sub <(DEPTH)/starboard/shared/starboard/player/testdata *.dmp.sha1 dmp.sha1 dmp)'],
+ 'inputs': [
+ '<!@pymod_do_main(starboard.build.gyp_functions file_glob <(sha_dir) *.dmp.sha1)',
+ ],
+ 'outputs': [
+ '<!@pymod_do_main(starboard.build.gyp_functions file_glob_sub <(DEPTH)/starboard/shared/starboard/player/testdata *.dmp.sha1 dmp.sha1 dmp)',
+ ],
},
],
'includes': ['<(DEPTH)/starboard/build/copy_test_data.gypi'],
diff --git a/src/starboard/stub/configuration_constants.cc b/src/starboard/stub/configuration_constants.cc
index c3e1c74..1ef685f 100644
--- a/src/starboard/stub/configuration_constants.cc
+++ b/src/starboard/stub/configuration_constants.cc
@@ -81,21 +81,6 @@
// video.
const uint32_t kSbMediaMaxVideoBitrateInBitsPerSecond = 200 * 1024 * 1024;
-// Specify the number of video frames to be cached during playback. A large
-// value leads to more stable fps but also causes the app to use more memory.
-const uint32_t kSbMediaMaximumVideoFrames = 12;
-
-// The encoded video frames are compressed in different ways, so their decoding
-// time can vary a lot. Occasionally a single frame can take longer time to
-// decode than the average time per frame. The player has to cache some frames
-// to account for such inconsistency. The number of frames being cached are
-// controlled by SB_MEDIA_MAXIMUM_VIDEO_PREROLL_FRAMES and
-// SB_MEDIA_MAXIMUM_VIDEO_FRAMES.
-//
-// Specify the number of video frames to be cached before the playback starts.
-// Note that setting this value too large may increase the playback start delay.
-const uint32_t kSbMediaMaximumVideoPrerollFrames = 4;
-
// Specifies how video frame buffers must be aligned on this platform.
const uint32_t kSbMediaVideoFrameAlignment = 256;
diff --git a/src/starboard/tools/app_launcher_packager.py b/src/starboard/tools/app_launcher_packager.py
index 902d8e0..d978de4 100644
--- a/src/starboard/tools/app_launcher_packager.py
+++ b/src/starboard/tools/app_launcher_packager.py
@@ -24,6 +24,7 @@
import logging
import os
import shutil
+import string
import sys
import tempfile
@@ -32,7 +33,6 @@
from paths import THIRD_PARTY_ROOT
sys.path.append(THIRD_PARTY_ROOT)
# pylint: disable=g-import-not-at-top,g-bad-import-order
-import jinja2
from starboard.tools import command_line
from starboard.tools import log_level
from starboard.tools import port_symlink
@@ -40,15 +40,12 @@
# Default python directories to app launcher resources.
_INCLUDE_FILE_PATTERNS = [
- ('buildbot', '*.py'),
+ ('buildbot', '_env.py'), # Only needed for device_server to execute
+ ('buildbot', '__init__.py'), # Only needed for device_server to execute
+ ('buildbot/device_server', '*.py'),
('buildbot/device_server/shared/ssl_certs', '*'),
('cobalt', '*.py'),
- # TODO: Test and possibly prune.
- ('lbshell', '*.py'),
('starboard', '*.py'),
- # jinja2 required by this app_launcher_packager.py script.
- ('third_party/jinja2', '*.py'),
- ('third_party/markupsafe', '*.py'), # Required by third_party/jinja2
]
_INCLUDE_BLACK_BOX_TESTS_PATTERNS = [
@@ -134,10 +131,11 @@
# Store posix paths even on Windows so MH Linux hosts can use them.
# The template has code to re-normalize them when used on Windows hosts.
platforms_map[p] = platform_path.replace('\\', '/')
- template = jinja2.Template(
+ template = string.Template(
open(os.path.join(current_dir, 'platform.py.template')).read())
with open(os.path.join(dest_dir, 'platform.py'), 'w+') as f:
- template.stream(platforms_map=platforms_map).dump(f, encoding='utf-8')
+ sub = template.substitute(platforms_map=platforms_map)
+ f.write(sub.encode('utf-8'))
logging.info('Finished baking in platform info files.')
@@ -258,9 +256,12 @@
action='store_true',
help='List to stdout the application resources relative to the current '
'directory.')
- parser.add_argument('-v', '--verbose', action='store_true',
- help='Enables verbose logging. For more control over the '
- "logging level use '--log_level' instead.")
+ parser.add_argument(
+ '-v',
+ '--verbose',
+ action='store_true',
+ help='Enables verbose logging. For more control over the '
+ "logging level use '--log_level' instead.")
args = parser.parse_args(command_args)
log_level.InitializeLogging(args)
diff --git a/src/starboard/tools/cache.py b/src/starboard/tools/cache.py
new file mode 100644
index 0000000..4839ffc
--- /dev/null
+++ b/src/starboard/tools/cache.py
@@ -0,0 +1,64 @@
+#
+# Copyright 2020 The Cobalt Authors. 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.
+#
+"""Cache specific definitions and helper functions.
+
+Override settings to enable/disable cache using environment variables. Default
+is None.
+"""
+
+import logging
+import os
+
+from starboard.tools import build_accelerator
+from starboard.tools import util
+
+
+class Accelerator:
+ CCACHE = ('ccache', 'USE_CCACHE')
+ # Windows compatible ccache.
+ SCCACHE = ('sccache.exe', 'USE_SCCACHE')
+
+
+class Cache(build_accelerator.BuildAccelerator):
+ """Cache based build accelerator."""
+
+ def __init__(self, accelerator):
+ self.binary, self.env_var = accelerator
+
+ def GetName(self):
+ return self.binary
+
+ def Use(self):
+ return self.EnvOverride() and self.BinaryInstalled()
+
+ def EnvOverride(self):
+ """Checks env_var to enable/disable cache.
+
+ Returns:
+ env_var boolean if exists, defaults to True.
+ """
+ if self.env_var in os.environ:
+ return os.environ[self.env_var] == '1'
+ return True
+
+ def BinaryInstalled(self):
+ """Returns True if binary is installed, otherwise is False."""
+ binary_path = util.Which(self.binary)
+ if binary_path is not None:
+ logging.info('Using %s installed at: %s', self.binary, binary_path)
+ return True
+ logging.info('Unable to find %s.', self.binary)
+ return False
diff --git a/src/starboard/tools/ccache.py b/src/starboard/tools/ccache.py
deleted file mode 100644
index 5f1928c..0000000
--- a/src/starboard/tools/ccache.py
+++ /dev/null
@@ -1,57 +0,0 @@
-#
-# Copyright 2020 The Cobalt Authors. 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.
-#
-"""Ccache specific definitions and helper functions.
-
-Override settings using environment variables.
-USE_CCACHE To enable/disable ccache. Default is None.
-"""
-
-import logging
-import os
-import util
-
-from starboard.tools import build_accelerator
-
-
-class Ccache(build_accelerator.BuildAccelerator):
- """Ccache is a cache based build accelerator."""
-
- def GetName(self):
- return 'ccache'
-
- def Use(self):
- return CcacheEnvOverride() and CcacheInstalled()
-
-
-def CcacheEnvOverride():
- """Checks USE_CCACHE to enable/disable ccache.
-
- Returns:
- USE_CCACHE boolean if exists, defaults to True.
- """
- if 'USE_CCACHE' in os.environ:
- return os.environ['USE_CCACHE'] == '1'
- return True
-
-
-def CcacheInstalled():
- """Returns True if ccache is installed, otherwise is False."""
- ccache_path = util.Which('ccache')
- if ccache_path is not None:
- logging.info('Using ccache installed at: %s', ccache_path)
- return True
- logging.error('Unable to find ccache.')
- return False
diff --git a/src/starboard/tools/find_private_files.py b/src/starboard/tools/find_private_files.py
deleted file mode 100644
index b63ee10..0000000
--- a/src/starboard/tools/find_private_files.py
+++ /dev/null
@@ -1,66 +0,0 @@
-#!/usr/bin/env python
-# Copyright 2017 The Cobalt Authors. 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.
-"""Gyp helper to find private files if present.
-
-The first argument is the result of "<(DEPTH)" from gyp, the second argument
-is the path/pattern from <(DEPTH)/starboard/private/. Patterns should be given
-using Unix path style '/'.
-
-python find_private_files.py "../.." "*.h"
-Would return files matching ../../starboard/private/*.h if any exist.
-
-python find_private_files.py "../.." "nplb/*_test.cc"
-Would return files matching ../../starboard/private/nplb/*_test.cc if any exist.
-
-NOTE: gyp errors often produce no warnings. Be sure to structure usages of this
-script by gyp files like the line below, where the'<!@' is a gyp command
-expansion that will process the results into a list of returned file paths.
-Quoting arguments protects against wildcard expansion and other undesirable
-gyp/shell behavior.
-'<!@(python "<(DEPTH)/starboard/tools/find_private_files.py" "<(DEPTH)" "*.h")',
-"""
-
-import glob
-import os
-import sys
-
-
-def find_private_files(depth,
- target_pattern,
- private_dir_path='starboard/private'):
- """Assembles search glob and finds files matching the target pattern.
-
- Args:
- depth: The string result of "<(DEPTH)"" from gyp.
- target_pattern: The string path/pattern from <(DEPTH)/|private_dir_path|
- private_dir_path: Optional The path to the private directory, which
- defaults to 'starboard/private'.
- """
- path = os.path.normpath(os.path.join(depth, private_dir_path, target_pattern))
- for f in glob.iglob(path):
- # Switch to Unix style '/' for gyp.
- print f.replace('\\', '/')
-
-
-if __name__ == '__main__':
- depth_arg = sys.argv[1]
- target_pattern_arg = sys.argv[2]
- if len(sys.argv) > 3:
- private_dir_path_arg = sys.argv[3]
- find_private_files(depth_arg, target_pattern_arg, private_dir_path_arg)
- else:
- find_private_files(depth_arg, target_pattern_arg)
-
- sys.exit(0)
diff --git a/src/starboard/tools/platform.py.template b/src/starboard/tools/platform.py.template
index 17d55b5..204d415 100644
--- a/src/starboard/tools/platform.py.template
+++ b/src/starboard/tools/platform.py.template
@@ -20,7 +20,7 @@
from starboard.tools import environment
# The name->platform path mapping.
-_PATH_MAP = {{platforms_map}}
+_PATH_MAP = $platforms_map
_PATH_MAP = {k:os.path.normpath(v) for k,v in _PATH_MAP.iteritems()}
diff --git a/src/starboard/tools/toolchain/msvc.py b/src/starboard/tools/toolchain/msvc.py
index 401ba5b..18032c4 100644
--- a/src/starboard/tools/toolchain/msvc.py
+++ b/src/starboard/tools/toolchain/msvc.py
@@ -50,24 +50,22 @@
return 'msvc'
def GetRspFilePath(self):
- return '$out.rsp'
+ return None
def GetRspFileContent(self):
- return self._command_flags
+ return None
def GetCommand(self, path, extra_flags, flags, shell):
del extra_flags # Not used.
del shell # Not used.
self._command_flags = flags
- return ('{path} /nologo /showIncludes /FC @$out.rsp /c $in /Fo$out '
- '/Fd$pdbname'.format(path=path))
+ return ('{path} /nologo /showIncludes {flags} /c $in /Fo$out'.format(
+ path=path, flags=flags))
def GetFlags(self, defines, include_dirs, cflags):
defines = defines + self._gyp_defines
quoted_defines = QuoteArguments(defines)
- define_flags = [
- '/D{0}'.format(define) for define in quoted_defines
- ]
+ define_flags = ['/D{0}'.format(define) for define in quoted_defines]
include_dirs = include_dirs + self._gyp_include_dirs
quoted_include_dirs = QuoteArguments(include_dirs)
include_dir_flags = [
@@ -128,8 +126,8 @@
del extra_flags # Not used.
del shell # Not used.
return ('{python} gyp-win-tool asm-wrapper {arch} {path} {flags} /c /Fo '
- '$out $in'.format(python=sys.executable, arch=self._arch,
- path=path, flags=flags))
+ '$out $in'.format(
+ python=sys.executable, arch=self._arch, path=path, flags=flags))
def GetDescription(self):
return 'ASM $in'
@@ -138,9 +136,7 @@
del cflags # Not used.
defines = defines + self._gyp_defines
quoted_defines = QuoteArguments(defines)
- define_flags = [
- '/D{0}'.format(define) for define in quoted_defines
- ]
+ define_flags = ['/D{0}'.format(define) for define in quoted_defines]
include_dirs = include_dirs + self._gyp_include_dirs
quoted_include_dirs = QuoteArguments(include_dirs)
include_dir_flags = [
@@ -156,6 +152,8 @@
self._path = common.GetPath('ar', **kwargs)
self._arch = kwargs.get('arch', 'environment.x64')
self._gyp_libflags = kwargs.get('gyp_libflags', [])
+ self._max_concurrent_processes = kwargs.get('max_concurrent_processes',
+ None)
def GetPath(self):
return self._path
@@ -165,8 +163,7 @@
return []
def GetMaxConcurrentProcesses(self):
- # Run as much concurrent processes as possible.
- return None
+ return self._max_concurrent_processes
def GetDescription(self):
return 'LIB $out'
@@ -182,9 +179,8 @@
del shell # Not used.
self._command_flags = flags
return ('{python} gyp-win-tool link-wrapper {arch} {path} /nologo '
- '/ignore:4221 /OUT:$out @$out.rsp'.format(python=sys.executable,
- arch=self._arch,
- path=path))
+ '/ignore:4221 /OUT:$out @$out.rsp'.format(
+ python=sys.executable, arch=self._arch, path=path))
def GetFlags(self):
return self._gyp_libflags
@@ -249,9 +245,8 @@
del shell # Not used.
self._command_flags = flags
return ('{python} gyp-win-tool link-wrapper {arch} {path} /nologo '
- '/OUT:$out /PDB:$out.pdb @$out.rsp'.format(python=sys.executable,
- arch=self._arch,
- path=path))
+ '/OUT:$out /PDB:$out.pdb @$out.rsp'.format(
+ python=sys.executable, arch=self._arch, path=path))
class SharedLibraryLinker(DynamicLinkerBase, abstract.SharedLibraryLinker):
@@ -274,9 +269,8 @@
del shell # Not used.
self._command_flags = flags
return ('{python} gyp-win-tool link-wrapper {arch} {path} /nologo '
- '$implibflag /DLL /OUT:$dll /PDB:$dll.pdb @$dll.rsp'.format(python=sys.executable,
- arch=self._arch,
- path=path))
+ '$implibflag /DLL /OUT:$dll /PDB:$dll.pdb @$dll.rsp'.format(
+ python=sys.executable, arch=self._arch, path=path))
def GetRestat(self):
return True
diff --git a/src/starboard/ui_navigation.h b/src/starboard/ui_navigation.h
index e110c43..11efefa 100644
--- a/src/starboard/ui_navigation.h
+++ b/src/starboard/ui_navigation.h
@@ -241,6 +241,15 @@
//
// Essentially, content items should be drawn at:
// [container position] + [content position] - [container content offset]
+#if SB_API_VERSION >= SB_UI_NAVIGATION2_VERSION
+ //
+ // Content items may overlap within a container. This can cause obscured items
+ // to be unfocusable. The only rule that needs to be followed is that contents
+ // which are focus items can obscure other contents which are containers, but
+ // not vice versa. The caller must ensure that content focus items do not
+ // overlap other content focus items and content container items do not
+ // overlap other content container items.
+#endif
void (*set_item_container_item)(SbUiNavItem item, SbUiNavItem container);
// Set the current content offset for the given container. This may be used
diff --git a/src/third_party/angle/angle.gyp b/src/third_party/angle/angle.gyp
index 8bb6ad8..b34eea7 100644
--- a/src/third_party/angle/angle.gyp
+++ b/src/third_party/angle/angle.gyp
@@ -55,6 +55,13 @@
'./src',
'./src/common/third_party/base',
],
+ 'msvs_settings':
+ {
+ 'VCCLCompilerTool':
+ {
+ 'WarnAsError': 'false',
+ },
+ },
'direct_dependent_settings':
{
'include_dirs':
diff --git a/src/third_party/angle/src/compiler.gypi b/src/third_party/angle/src/compiler.gypi
index 7be0ac3..4c87123 100644
--- a/src/third_party/angle/src/compiler.gypi
+++ b/src/third_party/angle/src/compiler.gypi
@@ -353,6 +353,13 @@
'dependencies': [ 'angle_common' ],
'includes': [ '../gyp/common_defines.gypi', ],
'sources': [ '<@(angle_preprocessor_sources)', ],
+ 'msvs_settings':
+ {
+ 'VCCLCompilerTool':
+ {
+ 'WarnAsError': 'false',
+ },
+ },
},
{
'target_name': 'translator',
@@ -370,10 +377,14 @@
],
'msvs_settings':
{
- 'VCLibrarianTool':
- {
- 'AdditionalOptions': ['/ignore:4221']
- },
+ 'VCCLCompilerTool':
+ {
+ 'WarnAsError': 'false',
+ },
+ 'VCLibrarianTool':
+ {
+ 'AdditionalOptions': ['/ignore:4221'],
+ },
},
'conditions':
[
diff --git a/src/third_party/freetype2/src/tools/Jamfile b/src/third_party/freetype2/src/tools/Jamfile
new file mode 100644
index 0000000..475161e
--- /dev/null
+++ b/src/third_party/freetype2/src/tools/Jamfile
@@ -0,0 +1,5 @@
+# Jamfile for src/tools
+#
+SubDir FT2_TOP src tools ;
+
+Main apinames : apinames.c ;
diff --git a/src/third_party/freetype2/src/tools/afblue.pl b/src/third_party/freetype2/src/tools/afblue.pl
new file mode 100644
index 0000000..bbc4f47
--- /dev/null
+++ b/src/third_party/freetype2/src/tools/afblue.pl
@@ -0,0 +1,551 @@
+#! /usr/bin/perl -w
+# -*- Perl -*-
+#
+# afblue.pl
+#
+# Process a blue zone character data file.
+#
+# Copyright (C) 2013-2020 by
+# David Turner, Robert Wilhelm, and Werner Lemberg.
+#
+# This file is part of the FreeType project, and may only be used,
+# modified, and distributed under the terms of the FreeType project
+# license, LICENSE.TXT. By continuing to use, modify, or distribute
+# this file you indicate that you have read the license and
+# understand and accept it fully.
+
+use strict;
+use warnings;
+use English '-no_match_vars';
+use open ':std', ':encoding(UTF-8)';
+
+
+my $prog = $PROGRAM_NAME;
+$prog =~ s| .* / ||x; # Remove path.
+
+die "usage: $prog datafile < infile > outfile\n" if $#ARGV != 0;
+
+
+my $datafile = $ARGV[0];
+
+my %diversions; # The extracted and massaged data from `datafile'.
+my @else_stack; # Booleans to track else-clauses.
+my @name_stack; # Stack of integers used for names of aux. variables.
+
+my $curr_enum; # Name of the current enumeration.
+my $curr_array; # Name of the current array.
+my $curr_max; # Name of the current maximum value.
+
+my $curr_enum_element; # Name of the current enumeration element.
+my $curr_offset; # The offset relative to current aux. variable.
+my $curr_elem_size; # The number of non-space characters in the current string or
+ # the number of elements in the current block.
+
+my $have_sections = 0; # Boolean; set if start of a section has been seen.
+my $have_strings; # Boolean; set if current section contains strings.
+my $have_blocks; # Boolean; set if current section contains blocks.
+
+my $have_enum_element; # Boolean; set if we have an enumeration element.
+my $in_string; # Boolean; set if a string has been parsed.
+
+my $num_sections = 0; # Number of sections seen so far.
+
+my $last_aux; # Name of last auxiliary variable.
+
+
+# Regular expressions.
+
+# [<ws>] <enum_name> <ws> <array_name> <ws> <max_name> [<ws>] ':' [<ws>] '\n'
+my $section_re = qr/ ^ \s* (\S+) \s+ (\S+) \s+ (\S+) \s* : \s* $ /x;
+
+# [<ws>] <enum_element_name> [<ws>] '\n'
+my $enum_element_re = qr/ ^ \s* ( [A-Za-z0-9_]+ ) \s* $ /x;
+
+# '#' <preprocessor directive> '\n'
+my $preprocessor_re = qr/ ^ \# /x;
+
+# [<ws>] '/' '/' <comment> '\n'
+my $comment_re = qr| ^ \s* // |x;
+
+# empty line
+my $whitespace_only_re = qr/ ^ \s* $ /x;
+
+# [<ws>] '"' <string> '"' [<ws>] '\n' (<string> doesn't contain newlines)
+my $string_re = qr/ ^ \s*
+ " ( (?> (?: (?> [^"\\]+ ) | \\. )* ) ) "
+ \s* $ /x;
+
+# [<ws>] '{' <block> '}' [<ws>] '\n' (<block> can contain newlines)
+my $block_start_re = qr/ ^ \s* \{ /x;
+
+# We need the capturing group for `split' to make it return the separator
+# tokens (i.e., the opening and closing brace) also.
+my $brace_re = qr/ ( [{}] ) /x;
+
+
+sub Warn
+{
+ my $message = shift;
+ warn "$datafile:$INPUT_LINE_NUMBER: warning: $message\n";
+}
+
+
+sub Die
+{
+ my $message = shift;
+ die "$datafile:$INPUT_LINE_NUMBER: error: $message\n";
+}
+
+
+my $warned_before = 0;
+
+sub warn_before
+{
+ Warn("data before first section gets ignored") unless $warned_before;
+ $warned_before = 1;
+}
+
+
+sub strip_newline
+{
+ chomp;
+ s/ \x0D $ //x;
+}
+
+
+sub end_curr_string
+{
+ # Append final null byte to string.
+ if ($have_strings)
+ {
+ push @{$diversions{$curr_array}}, " '\\0',\n" if $in_string;
+
+ $curr_offset++;
+ $in_string = 0;
+ }
+}
+
+
+sub update_max_elem_size
+{
+ if ($curr_elem_size)
+ {
+ my $max = pop @{$diversions{$curr_max}};
+ $max = $curr_elem_size if $curr_elem_size > $max;
+ push @{$diversions{$curr_max}}, $max;
+ }
+}
+
+
+sub convert_non_ascii_char
+{
+ # A UTF-8 character outside of the printable ASCII range, with possibly a
+ # leading backslash character.
+ my $s = shift;
+
+ # Here we count characters, not bytes.
+ $curr_elem_size += length $s;
+
+ utf8::encode($s);
+ $s = uc unpack 'H*', $s;
+
+ $curr_offset += $s =~ s/\G(..)/'\\x$1', /sg;
+
+ return $s;
+}
+
+
+sub convert_ascii_chars
+{
+ # A series of ASCII characters in the printable range.
+ my $s = shift;
+
+ # We reduce multiple space characters to a single one.
+ $s =~ s/ +/ /g;
+
+ # Count all non-space characters. Note that `()' applies a list context
+ # to the capture that is used to count the elements.
+ $curr_elem_size += () = $s =~ /[^ ]/g;
+
+ $curr_offset += $s =~ s/\G(.)/'$1', /g;
+
+ return $s;
+}
+
+
+sub convert_literal
+{
+ my $s = shift;
+ my $orig = $s;
+
+ # ASCII printables and space
+ my $safe_re = '\x20-\x7E';
+ # ASCII printables and space, no backslash
+ my $safe_no_backslash_re = '\x20-\x5B\x5D-\x7E';
+
+ $s =~ s{
+ (?: \\? ( [^$safe_re] )
+ | ( (?: [$safe_no_backslash_re]
+ | \\ [$safe_re] )+ ) )
+ }
+ {
+ defined($1) ? convert_non_ascii_char($1)
+ : convert_ascii_chars($2)
+ }egx;
+
+ # We assume that `$orig' doesn't contain `*/'
+ return $s . " /* $orig */";
+}
+
+
+sub aux_name
+{
+ return "af_blue_" . $num_sections. "_" . join('_', @name_stack);
+}
+
+
+sub aux_name_next
+{
+ $name_stack[$#name_stack]++;
+ my $name = aux_name();
+ $name_stack[$#name_stack]--;
+
+ return $name;
+}
+
+
+sub enum_val_string
+{
+ # Build string that holds code to save the current offset in an
+ # enumeration element.
+ my $aux = shift;
+
+ my $add = ($last_aux eq "af_blue_" . $num_sections . "_0" )
+ ? ""
+ : "$last_aux + ";
+
+ return " $aux = $add$curr_offset,\n";
+}
+
+
+
+# Process data file.
+
+open(DATA, $datafile) || die "$prog: can't open \`$datafile': $OS_ERROR\n";
+
+while (<DATA>)
+{
+ strip_newline();
+
+ next if /$comment_re/;
+ next if /$whitespace_only_re/;
+
+ if (/$section_re/)
+ {
+ Warn("previous section is empty") if ($have_sections
+ && !$have_strings
+ && !$have_blocks);
+
+ end_curr_string();
+ update_max_elem_size();
+
+ # Save captured groups from `section_re'.
+ $curr_enum = $1;
+ $curr_array = $2;
+ $curr_max = $3;
+
+ $curr_enum_element = "";
+ $curr_offset = 0;
+
+ Warn("overwriting already defined enumeration \`$curr_enum'")
+ if exists($diversions{$curr_enum});
+ Warn("overwriting already defined array \`$curr_array'")
+ if exists($diversions{$curr_array});
+ Warn("overwriting already defined maximum value \`$curr_max'")
+ if exists($diversions{$curr_max});
+
+ $diversions{$curr_enum} = [];
+ $diversions{$curr_array} = [];
+ $diversions{$curr_max} = [];
+
+ push @{$diversions{$curr_max}}, 0;
+
+ @name_stack = ();
+ push @name_stack, 0;
+
+ $have_sections = 1;
+ $have_strings = 0;
+ $have_blocks = 0;
+
+ $have_enum_element = 0;
+ $in_string = 0;
+
+ $num_sections++;
+ $curr_elem_size = 0;
+
+ $last_aux = aux_name();
+
+ next;
+ }
+
+ if (/$preprocessor_re/)
+ {
+ if ($have_sections)
+ {
+ # Having preprocessor conditionals complicates the computation of
+ # correct offset values. We have to introduce auxiliary enumeration
+ # elements with the name `af_blue_<s>_<n1>_<n2>_...' that store
+ # offsets to be used in conditional clauses. `<s>' is the number of
+ # sections seen so far, `<n1>' is the number of `#if' and `#endif'
+ # conditionals seen so far in the topmost level, `<n2>' the number of
+ # `#if' and `#endif' conditionals seen so far one level deeper, etc.
+ # As a consequence, uneven values are used within a clause, and even
+ # values after a clause, since the C standard doesn't allow the
+ # redefinition of an enumeration value. For example, the name
+ # `af_blue_5_1_6' is used to construct enumeration values in the fifth
+ # section after the third (second-level) if-clause within the first
+ # (top-level) if-clause. After the first top-level clause has
+ # finished, `af_blue_5_2' is used. The current offset is then
+ # relative to the value stored in the current auxiliary element.
+
+ if (/ ^ \# \s* if /x)
+ {
+ push @else_stack, 0;
+
+ $name_stack[$#name_stack]++;
+
+ push @{$diversions{$curr_enum}}, enum_val_string(aux_name());
+ $last_aux = aux_name();
+
+ push @name_stack, 0;
+
+ $curr_offset = 0;
+ }
+ elsif (/ ^ \# \s* elif /x)
+ {
+ Die("unbalanced #elif") unless @else_stack;
+
+ pop @name_stack;
+
+ push @{$diversions{$curr_enum}}, enum_val_string(aux_name_next());
+ $last_aux = aux_name();
+
+ push @name_stack, 0;
+
+ $curr_offset = 0;
+ }
+ elsif (/ ^ \# \s* else /x)
+ {
+ my $prev_else = pop @else_stack;
+ Die("unbalanced #else") unless defined($prev_else);
+ Die("#else already seen") if $prev_else;
+ push @else_stack, 1;
+
+ pop @name_stack;
+
+ push @{$diversions{$curr_enum}}, enum_val_string(aux_name_next());
+ $last_aux = aux_name();
+
+ push @name_stack, 0;
+
+ $curr_offset = 0;
+ }
+ elsif (/ ^ (\# \s*) endif /x)
+ {
+ my $prev_else = pop @else_stack;
+ Die("unbalanced #endif") unless defined($prev_else);
+
+ pop @name_stack;
+
+ # If there is no else-clause for an if-clause, we add one. This is
+ # necessary to have correct offsets.
+ if (!$prev_else)
+ {
+ # Use amount of whitespace from `endif'.
+ push @{$diversions{$curr_enum}}, enum_val_string(aux_name_next())
+ . $1 . "else\n";
+ $last_aux = aux_name();
+
+ $curr_offset = 0;
+ }
+
+ $name_stack[$#name_stack]++;
+
+ push @{$diversions{$curr_enum}}, enum_val_string(aux_name());
+ $last_aux = aux_name();
+
+ $curr_offset = 0;
+ }
+
+ # Handle (probably continued) preprocessor lines.
+ CONTINUED_LOOP:
+ {
+ do
+ {
+ strip_newline();
+
+ push @{$diversions{$curr_enum}}, $ARG . "\n";
+ push @{$diversions{$curr_array}}, $ARG . "\n";
+
+ last CONTINUED_LOOP unless / \\ $ /x;
+
+ } while (<DATA>);
+ }
+ }
+ else
+ {
+ warn_before();
+ }
+
+ next;
+ }
+
+ if (/$enum_element_re/)
+ {
+ end_curr_string();
+ update_max_elem_size();
+
+ $curr_enum_element = $1;
+ $have_enum_element = 1;
+ $curr_elem_size = 0;
+
+ next;
+ }
+
+ if (/$string_re/)
+ {
+ if ($have_sections)
+ {
+ Die("strings and blocks can't be mixed in a section") if $have_blocks;
+
+ # Save captured group from `string_re'.
+ my $string = $1;
+
+ if ($have_enum_element)
+ {
+ push @{$diversions{$curr_enum}}, enum_val_string($curr_enum_element);
+ $have_enum_element = 0;
+ }
+
+ $string = convert_literal($string);
+
+ push @{$diversions{$curr_array}}, " $string\n";
+
+ $have_strings = 1;
+ $in_string = 1;
+ }
+ else
+ {
+ warn_before();
+ }
+
+ next;
+ }
+
+ if (/$block_start_re/)
+ {
+ if ($have_sections)
+ {
+ Die("strings and blocks can't be mixed in a section") if $have_strings;
+
+ my $depth = 0;
+ my $block = "";
+ my $block_end = 0;
+
+ # Count braces while getting the block.
+ BRACE_LOOP:
+ {
+ do
+ {
+ strip_newline();
+
+ foreach my $substring (split(/$brace_re/))
+ {
+ if ($block_end)
+ {
+ Die("invalid data after last matching closing brace")
+ if $substring !~ /$whitespace_only_re/;
+ }
+
+ $block .= $substring;
+
+ if ($substring eq '{')
+ {
+ $depth++;
+ }
+ elsif ($substring eq '}')
+ {
+ $depth--;
+
+ $block_end = 1 if $depth == 0;
+ }
+ }
+
+ # If we are here, we have run out of substrings, so get next line
+ # or exit.
+ last BRACE_LOOP if $block_end;
+
+ $block .= "\n";
+
+ } while (<DATA>);
+ }
+
+ if ($have_enum_element)
+ {
+ push @{$diversions{$curr_enum}}, enum_val_string($curr_enum_element);
+ $have_enum_element = 0;
+ }
+
+ push @{$diversions{$curr_array}}, $block . ",\n";
+
+ $curr_offset++;
+ $curr_elem_size++;
+
+ $have_blocks = 1;
+ }
+ else
+ {
+ warn_before();
+ }
+
+ next;
+ }
+
+ # Garbage. We weren't able to parse the data.
+ Die("syntax error");
+}
+
+# Finalize data.
+end_curr_string();
+update_max_elem_size();
+
+
+# Filter stdin to stdout, replacing `@...@' templates.
+
+sub emit_diversion
+{
+ my $diversion_name = shift;
+ return (exists($diversions{$1})) ? "@{$diversions{$1}}"
+ : "@" . $diversion_name . "@";
+}
+
+
+$LIST_SEPARATOR = '';
+
+my $s1 = "This file has been generated by the Perl script \`$prog',";
+my $s1len = length $s1;
+my $s2 = "using data from file \`$datafile'.";
+my $s2len = length $s2;
+my $slen = ($s1len > $s2len) ? $s1len : $s2len;
+
+print "/* " . $s1 . " " x ($slen - $s1len) . " */\n"
+ . "/* " . $s2 . " " x ($slen - $s2len) . " */\n"
+ . "\n";
+
+while (<STDIN>)
+{
+ s/ @ ( [A-Za-z0-9_]+? ) @ / emit_diversion($1) /egx;
+ print;
+}
+
+# EOF
diff --git a/src/third_party/freetype2/src/tools/apinames.c b/src/third_party/freetype2/src/tools/apinames.c
new file mode 100644
index 0000000..aeecf88
--- /dev/null
+++ b/src/third_party/freetype2/src/tools/apinames.c
@@ -0,0 +1,514 @@
+/*
+ * This little program is used to parse the FreeType headers and
+ * find the declaration of all public APIs. This is easy, because
+ * they all look like the following:
+ *
+ * FT_EXPORT( return_type )
+ * function_name( function arguments );
+ *
+ * You must pass the list of header files as arguments. Wildcards are
+ * accepted if you are using GCC for compilation (and probably by
+ * other compilers too).
+ *
+ * Author: FreeType team, 2005-2019
+ *
+ * This code is explicitly placed into the public domain.
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+
+#define PROGRAM_NAME "apinames"
+#define PROGRAM_VERSION "0.3"
+
+#define LINEBUFF_SIZE 1024
+
+
+typedef enum OutputFormat_
+{
+ OUTPUT_LIST = 0, /* output the list of names, one per line */
+ OUTPUT_WINDOWS_DEF, /* output a Windows .DEF file for Visual C++ or Mingw */
+ OUTPUT_BORLAND_DEF, /* output a Windows .DEF file for Borland C++ */
+ OUTPUT_WATCOM_LBC, /* output a Watcom Linker Command File */
+ OUTPUT_NETWARE_IMP, /* output a NetWare ImportFile */
+ OUTPUT_GNU_VERMAP /* output a version map for GNU or Solaris linker */
+
+} OutputFormat;
+
+
+static void
+panic( const char* message )
+{
+ fprintf( stderr, "PANIC: %s\n", message );
+ exit(2);
+}
+
+
+typedef struct NameRec_
+{
+ char* name;
+ unsigned int hash;
+
+} NameRec, *Name;
+
+
+static Name the_names;
+static int num_names;
+static int max_names;
+
+
+static void
+names_add( const char* name,
+ const char* end )
+{
+ unsigned int h;
+ int nn, len;
+ Name nm;
+
+
+ if ( end <= name )
+ return;
+
+ /* compute hash value */
+ len = (int)( end - name );
+ h = 0;
+
+ for ( nn = 0; nn < len; nn++ )
+ h = h * 33 + name[nn];
+
+ /* check for an pre-existing name */
+ for ( nn = 0; nn < num_names; nn++ )
+ {
+ nm = the_names + nn;
+
+ if ( (int)nm->hash == h &&
+ memcmp( name, nm->name, len ) == 0 &&
+ nm->name[len] == 0 )
+ return;
+ }
+
+ /* add new name */
+ if ( num_names >= max_names )
+ {
+ max_names += ( max_names >> 1 ) + 4;
+ the_names = (NameRec*)realloc( the_names,
+ sizeof ( the_names[0] ) * max_names );
+ if ( !the_names )
+ panic( "not enough memory" );
+ }
+ nm = &the_names[num_names++];
+
+ nm->hash = h;
+ nm->name = (char*)malloc( len + 1 );
+ if ( !nm->name )
+ panic( "not enough memory" );
+
+ memcpy( nm->name, name, len );
+ nm->name[len] = 0;
+}
+
+
+static int
+name_compare( const void* name1,
+ const void* name2 )
+{
+ Name n1 = (Name)name1;
+ Name n2 = (Name)name2;
+
+ return strcmp( n1->name, n2->name );
+}
+
+
+static void
+names_sort( void )
+{
+ qsort( the_names, (size_t)num_names,
+ sizeof ( the_names[0] ), name_compare );
+}
+
+
+static void
+names_dump( FILE* out,
+ OutputFormat format,
+ const char* dll_name )
+{
+ int nn;
+
+
+ switch ( format )
+ {
+ case OUTPUT_WINDOWS_DEF:
+ if ( dll_name )
+ fprintf( out, "LIBRARY %s\n", dll_name );
+
+ fprintf( out, "DESCRIPTION FreeType 2 DLL\n" );
+ fprintf( out, "EXPORTS\n" );
+
+ for ( nn = 0; nn < num_names; nn++ )
+ fprintf( out, " %s\n", the_names[nn].name );
+
+ break;
+
+ case OUTPUT_BORLAND_DEF:
+ if ( dll_name )
+ fprintf( out, "LIBRARY %s\n", dll_name );
+
+ fprintf( out, "DESCRIPTION FreeType 2 DLL\n" );
+ fprintf( out, "EXPORTS\n" );
+
+ for ( nn = 0; nn < num_names; nn++ )
+ fprintf( out, " _%s\n", the_names[nn].name );
+
+ break;
+
+ case OUTPUT_WATCOM_LBC:
+ {
+ const char* dot;
+ char temp[512];
+
+
+ if ( !dll_name )
+ {
+ fprintf( stderr,
+ "you must provide a DLL name with the -d option!\n" );
+ exit( 4 );
+ }
+
+ /* we must omit the `.dll' suffix from the library name */
+ dot = strchr( dll_name, '.' );
+ if ( dot )
+ {
+ int len = dot - dll_name;
+
+
+ if ( len > (int)( sizeof ( temp ) - 1 ) )
+ len = sizeof ( temp ) - 1;
+
+ memcpy( temp, dll_name, len );
+ temp[len] = 0;
+
+ dll_name = (const char*)temp;
+ }
+
+ for ( nn = 0; nn < num_names; nn++ )
+ fprintf( out, "++_%s.%s.%s\n",
+ the_names[nn].name, dll_name, the_names[nn].name );
+ }
+
+ break;
+
+ case OUTPUT_NETWARE_IMP:
+ if ( dll_name )
+ fprintf( out, " (%s)\n", dll_name );
+
+ for ( nn = 0; nn < num_names - 1; nn++ )
+ fprintf( out, " %s,\n", the_names[nn].name );
+ fprintf( out, " %s\n", the_names[num_names - 1].name );
+
+ break;
+
+ case OUTPUT_GNU_VERMAP:
+ fprintf( out, "{\n\tglobal:\n" );
+
+ for ( nn = 0; nn < num_names; nn++ )
+ fprintf( out, "\t\t%s;\n", the_names[nn].name );
+
+ fprintf( out, "\tlocal:\n\t\t*;\n};\n" );
+
+ break;
+
+ default: /* LIST */
+ for ( nn = 0; nn < num_names; nn++ )
+ fprintf( out, "%s\n", the_names[nn].name );
+
+ break;
+ }
+}
+
+
+/* states of the line parser */
+
+typedef enum State_
+{
+ STATE_START = 0, /* waiting for FT_EXPORT keyword and return type */
+ STATE_TYPE /* type was read, waiting for function name */
+
+} State;
+
+
+static int
+read_header_file( FILE* file,
+ int verbose )
+{
+ static char buff[LINEBUFF_SIZE + 1];
+ State state = STATE_START;
+
+
+ while ( !feof( file ) )
+ {
+ char* p;
+
+
+ if ( !fgets( buff, LINEBUFF_SIZE, file ) )
+ break;
+
+ p = buff;
+
+ /* skip leading whitespace */
+ while ( *p && ( *p == ' ' || *p == '\\' ) )
+ p++;
+
+ /* skip empty lines */
+ if ( *p == '\n' || *p == '\r' )
+ continue;
+
+ switch ( state )
+ {
+ case STATE_START:
+ if ( memcmp( p, "FT_EXPORT(", 10 ) != 0 )
+ break;
+
+ p += 10;
+ for (;;)
+ {
+ if ( *p == 0 || *p == '\n' || *p == '\r' )
+ goto NextLine;
+
+ if ( *p == ')' )
+ {
+ p++;
+ break;
+ }
+
+ p++;
+ }
+
+ state = STATE_TYPE;
+
+ /*
+ * Sometimes, the name is just after `FT_EXPORT(...)', so skip
+ * whitespace and fall-through if we find an alphanumeric character.
+ */
+ while ( *p == ' ' || *p == '\t' )
+ p++;
+
+ if ( !isalpha( *p ) )
+ break;
+
+ /* fall-through */
+
+ case STATE_TYPE:
+ {
+ char* name = p;
+
+
+ while ( isalnum( *p ) || *p == '_' )
+ p++;
+
+ if ( p > name )
+ {
+ if ( verbose )
+ fprintf( stderr, ">>> %.*s\n", (int)( p - name ), name );
+
+ names_add( name, p );
+ }
+
+ state = STATE_START;
+ }
+
+ break;
+
+ default:
+ ;
+ }
+
+NextLine:
+ ;
+ } /* end of while loop */
+
+ return 0;
+}
+
+
+static void
+usage( void )
+{
+ static const char* const format =
+ "%s %s: extract FreeType API names from header files\n"
+ "\n"
+ "This program extracts the list of public FreeType API functions.\n"
+ "It receives a list of header files as an argument and\n"
+ "generates a sorted list of unique identifiers in various formats.\n"
+ "\n"
+ "usage: %s header1 [options] [header2 ...]\n"
+ "\n"
+ "options: - parse the contents of stdin, ignore arguments\n"
+ " -v verbose mode, output sent to standard error\n"
+ " -oFILE write output to FILE instead of standard output\n"
+ " -dNAME indicate DLL file name, 'freetype.dll' by default\n"
+ " -w output .DEF file for Visual C++ and Mingw\n"
+ " -wB output .DEF file for Borland C++\n"
+ " -wW output Watcom Linker Response File\n"
+ " -wN output NetWare Import File\n"
+ " -wL output version map for GNU or Solaris linker\n"
+ "\n";
+
+ fprintf( stderr,
+ format,
+ PROGRAM_NAME,
+ PROGRAM_VERSION,
+ PROGRAM_NAME );
+
+ exit( 1 );
+}
+
+
+int
+main( int argc,
+ const char* const* argv )
+{
+ int from_stdin = 0;
+ int verbose = 0;
+ OutputFormat format = OUTPUT_LIST; /* the default */
+ FILE* out = stdout;
+ const char* library_name = NULL;
+
+
+ if ( argc < 2 )
+ usage();
+
+ /* `-' used as a single argument means read source file from stdin */
+ while ( argc > 1 && argv[1][0] == '-' )
+ {
+ const char* arg = argv[1];
+
+
+ switch ( arg[1] )
+ {
+ case 'v':
+ verbose = 1;
+
+ break;
+
+ case 'o':
+ if ( arg[2] == 0 )
+ {
+ if ( argc < 2 )
+ usage();
+
+ arg = argv[2];
+ argv++;
+ argc--;
+ }
+ else
+ arg += 2;
+
+ out = fopen( arg, "wt" );
+ if ( !out )
+ {
+ fprintf( stderr, "could not open '%s' for writing\n", arg );
+ exit( 3 );
+ }
+
+ break;
+
+ case 'd':
+ if ( arg[2] == 0 )
+ {
+ if ( argc < 2 )
+ usage();
+
+ arg = argv[2];
+ argv++;
+ argc--;
+ }
+ else
+ arg += 2;
+
+ library_name = arg;
+
+ break;
+
+ case 'w':
+ format = OUTPUT_WINDOWS_DEF;
+
+ switch ( arg[2] )
+ {
+ case 'B':
+ format = OUTPUT_BORLAND_DEF;
+ break;
+
+ case 'W':
+ format = OUTPUT_WATCOM_LBC;
+ break;
+
+ case 'N':
+ format = OUTPUT_NETWARE_IMP;
+ break;
+
+ case 'L':
+ format = OUTPUT_GNU_VERMAP;
+ break;
+
+ case 0:
+ break;
+
+ default:
+ usage();
+ }
+
+ break;
+
+ case 0:
+ from_stdin = 1;
+
+ break;
+
+ default:
+ usage();
+ }
+
+ argc--;
+ argv++;
+
+ } /* end of while loop */
+
+ if ( from_stdin )
+ read_header_file( stdin, verbose );
+ else
+ {
+ for ( --argc, argv++; argc > 0; argc--, argv++ )
+ {
+ FILE* file = fopen( argv[0], "rb" );
+
+
+ if ( !file )
+ fprintf( stderr, "unable to open '%s'\n", argv[0] );
+ else
+ {
+ if ( verbose )
+ fprintf( stderr, "opening '%s'\n", argv[0] );
+
+ read_header_file( file, verbose );
+ fclose( file );
+ }
+ }
+ }
+
+ if ( num_names == 0 )
+ panic( "could not find exported functions\n" );
+
+ names_sort();
+ names_dump( out, format, library_name );
+
+ if ( out != stdout )
+ fclose( out );
+
+ return 0;
+}
+
+
+/* END */
diff --git a/src/third_party/freetype2/src/tools/ftrandom/Makefile b/src/third_party/freetype2/src/tools/ftrandom/Makefile
new file mode 100644
index 0000000..24dc49c
--- /dev/null
+++ b/src/third_party/freetype2/src/tools/ftrandom/Makefile
@@ -0,0 +1,45 @@
+# TOP_DIR and OBJ_DIR should be set by the user to the right directories,
+# if necessary.
+
+TOP_DIR ?= ../../..
+OBJ_DIR ?= $(TOP_DIR)/objs
+
+
+# The setup below is for gcc on a Unix-like platform,
+# where FreeType has been set up to create a static library
+# (which is the default).
+
+VPATH = $(OBJ_DIR) \
+ $(OBJ_DIR)/.libs
+
+SRC_DIR = $(TOP_DIR)/src/tools/ftrandom
+
+CC = gcc
+WFLAGS = -Wmissing-prototypes \
+ -Wunused \
+ -Wimplicit \
+ -Wreturn-type \
+ -Wparentheses \
+ -pedantic \
+ -Wformat \
+ -Wchar-subscripts \
+ -Wsequence-point
+CFLAGS = $(WFLAGS) \
+ -g
+INCLUDES = -I $(TOP_DIR)/include
+LDFLAGS =
+LIBS = -lm \
+ -lz \
+ -lpng \
+ -lbz2 \
+ -lharfbuzz
+
+all: $(OBJ_DIR)/ftrandom
+
+$(OBJ_DIR)/ftrandom.o: $(SRC_DIR)/ftrandom.c
+ $(CC) $(CFLAGS) $(INCLUDES) -c -o $@ $<
+
+$(OBJ_DIR)/ftrandom: $(OBJ_DIR)/ftrandom.o libfreetype.a
+ $(CC) $(LDFLAGS) -o $@ $^ $(LIBS)
+
+# EOF
diff --git a/src/third_party/freetype2/src/tools/ftrandom/README b/src/third_party/freetype2/src/tools/ftrandom/README
new file mode 100644
index 0000000..7c61086
--- /dev/null
+++ b/src/third_party/freetype2/src/tools/ftrandom/README
@@ -0,0 +1,69 @@
+ftrandom
+========
+
+This program expects a set of directories containing good fonts, and a set
+of extensions of fonts to be tested. It will randomly pick a font, copy it,
+introduce an error and then test it.
+
+The FreeType tests are quite basic; for each erroneous font ftrandom
+
+ . forks off a new tester,
+ . initializes the library,
+ . opens each font in the file,
+ . loads each glyph,
+ . optionally reviews the contours of the glyph,
+ . optionally rasterizes the glyph, and
+ . closes the face.
+
+If a tester takes longer than 20 seconds, ftrandom saves the erroneous font
+and continues. If the tester exits normally or with an error, then the
+superstructure removes the test font and continues.
+
+
+Command line options
+--------------------
+
+ --all Test every font in the directory(ies) no matter
+ what its extension.
+ --check-outlines Call `FT_Outline_Decompose' on each glyph.
+ --dir <dir> Append <dir> to the list of directories to search
+ for good fonts. No recursive search.
+ --error-count <cnt> Introduce <cnt> single-byte errors into the
+ erroneous fonts (default: 1).
+ --error-fraction <frac> Multiply the file size of the font by <frac> and
+ introduce that many errors into the erroneous
+ font file. <frac> should be in the range [0;1]
+ (default: 0.0).
+ --ext <ext> Add <ext> to the set of font types tested.
+ --help Print out this list of options.
+ --nohints Specify FT_LOAD_NO_HINTING when loading glyphs.
+ --rasterize Call `FT_Render_Glyph' as well as loading it.
+ --result <dir> This is the directory in which test files are
+ placed.
+ --test <file> Run a single test on a pre-generated testcase.
+ This is done in the current process so it can be
+ debugged more easily.
+
+The default font extensions tested by ftrandom are
+
+ .ttf .otf .ttc .cid .pfb .pfa .bdf .pcf .pfr .fon .otb .cff
+
+The default font directory is controlled by the macro `GOOD_FONTS_DIR' in
+the source code (and can be thus specified during compilation); its default
+value is
+
+ /usr/local/share/fonts
+
+The default result directory is `results' (in the current directory).
+
+
+Compilation
+-----------
+
+Two possible solutions.
+
+. Run ftrandom within a debugging tool like `valgrind' to catch various
+ memory issues.
+
+. Compile FreeType with sanitizer flags as provided by gcc or clang, for
+ example, then link it with ftrandom.
diff --git a/src/third_party/freetype2/src/tools/ftrandom/ftrandom.c b/src/third_party/freetype2/src/tools/ftrandom/ftrandom.c
new file mode 100644
index 0000000..ab5cfc9
--- /dev/null
+++ b/src/third_party/freetype2/src/tools/ftrandom/ftrandom.c
@@ -0,0 +1,720 @@
+/* Copyright (C) 2005, 2007, 2008, 2013 by George Williams */
+/*
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+
+ * The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/* modified by Werner Lemberg <wl@gnu.org> */
+/* This file is now part of the FreeType library */
+
+
+#define _XOPEN_SOURCE 500 /* for `kill', `strdup', `random', and `srandom' */
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <strings.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/wait.h>
+#include <unistd.h>
+#include <dirent.h>
+#include <signal.h>
+#include <time.h>
+
+#include <ft2build.h>
+#include FT_FREETYPE_H
+#include FT_OUTLINE_H
+
+#define true 1
+#define false 0
+#define forever for (;;)
+
+
+ static int check_outlines = false;
+ static int nohints = false;
+ static int rasterize = false;
+ static char* results_dir = "results";
+
+#define GOOD_FONTS_DIR "/usr/local/share/fonts"
+
+ static char* default_dir_list[] =
+ {
+ GOOD_FONTS_DIR,
+ NULL
+ };
+
+ static char* default_ext_list[] =
+ {
+ "ttf",
+ "otf",
+ "ttc",
+ "cid",
+ "pfb",
+ "pfa",
+ "bdf",
+ "pcf",
+ "pfr",
+ "fon",
+ "otb",
+ "cff",
+ NULL
+ };
+
+ static unsigned int error_count = 1;
+ static double error_fraction = 0.0;
+
+ static FT_F26Dot6 font_size = 12 * 64;
+
+ static struct fontlist
+ {
+ char* name;
+ long len;
+ unsigned int isbinary: 1;
+ unsigned int isascii: 1;
+ unsigned int ishex: 1;
+
+ } *fontlist;
+
+ static unsigned int fcnt;
+
+
+ static int
+ FT_MoveTo( const FT_Vector *to,
+ void *user )
+ {
+ FT_UNUSED( to );
+ FT_UNUSED( user );
+
+ return 0;
+ }
+
+
+ static int
+ FT_LineTo( const FT_Vector *to,
+ void *user )
+ {
+ FT_UNUSED( to );
+ FT_UNUSED( user );
+
+ return 0;
+ }
+
+
+ static int
+ FT_ConicTo( const FT_Vector *_cp,
+ const FT_Vector *to,
+ void *user )
+ {
+ FT_UNUSED( _cp );
+ FT_UNUSED( to );
+ FT_UNUSED( user );
+
+ return 0;
+ }
+
+
+ static int
+ FT_CubicTo( const FT_Vector *cp1,
+ const FT_Vector *cp2,
+ const FT_Vector *to,
+ void *user )
+ {
+ FT_UNUSED( cp1 );
+ FT_UNUSED( cp2 );
+ FT_UNUSED( to );
+ FT_UNUSED( user );
+
+ return 0;
+ }
+
+
+ static FT_Outline_Funcs outlinefuncs =
+ {
+ FT_MoveTo,
+ FT_LineTo,
+ FT_ConicTo,
+ FT_CubicTo,
+ 0, 0 /* No shift, no delta */
+ };
+
+
+ static void
+ TestFace( FT_Face face )
+ {
+ unsigned int gid;
+ int load_flags = FT_LOAD_DEFAULT;
+
+
+ if ( check_outlines &&
+ FT_IS_SCALABLE( face ) )
+ load_flags = FT_LOAD_NO_BITMAP;
+
+ if ( nohints )
+ load_flags |= FT_LOAD_NO_HINTING;
+
+ FT_Set_Char_Size( face, 0, font_size, 72, 72 );
+
+ for ( gid = 0; gid < face->num_glyphs; gid++ )
+ {
+ if ( check_outlines &&
+ FT_IS_SCALABLE( face ) )
+ {
+ if ( !FT_Load_Glyph( face, gid, load_flags ) )
+ FT_Outline_Decompose( &face->glyph->outline, &outlinefuncs, NULL );
+ }
+ else
+ FT_Load_Glyph( face, gid, load_flags );
+
+ if ( rasterize )
+ FT_Render_Glyph( face->glyph, ft_render_mode_normal );
+ }
+
+ FT_Done_Face( face );
+ }
+
+
+ static void
+ ExecuteTest( char* testfont )
+ {
+ FT_Library context;
+ FT_Face face;
+
+
+ if ( FT_Init_FreeType( &context ) )
+ {
+ fprintf( stderr, "Can't initialize FreeType.\n" );
+ exit( 1 );
+ }
+
+ if ( FT_New_Face( context, testfont, 0, &face ) )
+ {
+ /* The font is erroneous, so if this fails that's ok. */
+ exit( 0 );
+ }
+
+ if ( face->num_faces == 1 )
+ TestFace( face );
+ else
+ {
+ long i, num;
+
+
+ num = face->num_faces;
+ FT_Done_Face( face );
+
+ for ( i = 0; i < num; i++ )
+ {
+ if ( !FT_New_Face( context, testfont, i, &face ) )
+ TestFace( face );
+ }
+ }
+
+ FT_Done_FreeType( context );
+
+ exit( 0 );
+ }
+
+
+ static int
+ extmatch( char* filename,
+ char** extensions )
+ {
+ int i;
+ char* pt;
+
+
+ if ( !extensions )
+ return true;
+
+ pt = strrchr( filename, '.' );
+ if ( !pt )
+ return false;
+ if ( pt < strrchr( filename, '/' ) )
+ return false;
+
+ for ( i = 0; extensions[i] != NULL; i++ )
+ if ( strcasecmp( pt + 1, extensions[i] ) == 0 ||
+ strcasecmp( pt, extensions[i] ) == 0 )
+ return true;
+
+ return false;
+ }
+
+
+ static void
+ figurefiletype( struct fontlist* item )
+ {
+ FILE* foo;
+
+
+ item->isbinary = item->isascii = item->ishex = false;
+
+ foo = fopen( item->name, "rb" );
+ if ( foo )
+ {
+ /* Try to guess the file type from the first few characters... */
+ int ch1 = getc( foo );
+ int ch2 = getc( foo );
+ int ch3 = getc( foo );
+ int ch4 = getc( foo );
+
+
+ fclose( foo );
+
+ if ( ( ch1 == 0 && ch2 == 1 && ch3 == 0 && ch4 == 0 ) ||
+ ( ch1 == 'O' && ch2 == 'T' && ch3 == 'T' && ch4 == 'O' ) ||
+ ( ch1 == 't' && ch2 == 'r' && ch3 == 'u' && ch4 == 'e' ) ||
+ ( ch1 == 't' && ch2 == 't' && ch3 == 'c' && ch4 == 'f' ) )
+ {
+ /* ttf, otf, ttc files */
+ item->isbinary = true;
+ }
+ else if ( ch1 == 0x80 && ch2 == '\01' )
+ {
+ /* PFB header */
+ item->isbinary = true;
+ }
+ else if ( ch1 == '%' && ch2 == '!' )
+ {
+ /* Random PostScript */
+ if ( strstr( item->name, ".pfa" ) ||
+ strstr( item->name, ".PFA" ) )
+ item->ishex = true;
+ else
+ item->isascii = true;
+ }
+ else if ( ch1 == 1 && ch2 == 0 && ch3 == 4 )
+ {
+ /* Bare CFF */
+ item->isbinary = true;
+ }
+ else if ( ch1 == 'S' && ch2 == 'T' && ch3 == 'A' && ch4 == 'R' )
+ {
+ /* BDF */
+ item->ishex = true;
+ }
+ else if ( ch1 == 'P' && ch2 == 'F' && ch3 == 'R' && ch4 == '0' )
+ {
+ /* PFR */
+ item->isbinary = true;
+ }
+ else if ( ( ch1 == '\1' && ch2 == 'f' && ch3 == 'c' && ch4 == 'p' ) ||
+ ( ch1 == 'M' && ch2 == 'Z' ) )
+ {
+ /* Windows FON */
+ item->isbinary = true;
+ }
+ else
+ {
+ fprintf( stderr,
+ "Can't recognize file type of `%s', assuming binary\n",
+ item->name );
+ item->isbinary = true;
+ }
+ }
+ else
+ {
+ fprintf( stderr, "Can't open `%s' for typing the file.\n",
+ item->name );
+ item->isbinary = true;
+ }
+ }
+
+
+ static void
+ FindFonts( char** fontdirs,
+ char** extensions )
+ {
+ int i;
+ unsigned int max;
+ char buffer[1025];
+ struct stat statb;
+
+
+ max = 0;
+ fcnt = 0;
+
+ for ( i = 0; fontdirs[i] != NULL; i++ )
+ {
+ DIR* examples;
+ struct dirent* ent;
+
+
+ examples = opendir( fontdirs[i] );
+ if ( !examples )
+ {
+ fprintf( stderr,
+ "Can't open example font directory `%s'\n",
+ fontdirs[i] );
+ exit( 1 );
+ }
+
+ while ( ( ent = readdir( examples ) ) != NULL )
+ {
+ snprintf( buffer, sizeof ( buffer ),
+ "%s/%s", fontdirs[i], ent->d_name );
+ if ( stat( buffer, &statb ) == -1 || S_ISDIR( statb.st_mode ) )
+ continue;
+ if ( !extensions || extmatch( buffer, extensions ) )
+ {
+ if ( fcnt >= max )
+ {
+ max += 100;
+ fontlist = realloc( fontlist, max * sizeof ( struct fontlist ) );
+ if ( !fontlist )
+ {
+ fprintf( stderr, "Can't allocate memory\n" );
+ exit( 1 );
+ }
+ }
+
+ fontlist[fcnt].name = strdup( buffer );
+ fontlist[fcnt].len = statb.st_size;
+
+ figurefiletype( &fontlist[fcnt] );
+ fcnt++;
+ }
+ }
+
+ closedir( examples );
+ }
+
+ if ( fcnt == 0 )
+ {
+ fprintf( stderr, "Can't find matching font files.\n" );
+ exit( 1 );
+ }
+
+ fontlist[fcnt].name = NULL;
+ }
+
+
+ static unsigned int
+ getErrorCnt( struct fontlist* item )
+ {
+ if ( error_count == 0 && error_fraction == 0.0 )
+ return 0;
+
+ return error_count + (unsigned int)( error_fraction * item->len );
+ }
+
+
+ static int
+ getRandom( int low,
+ int high )
+ {
+ if ( low - high < 0x10000L )
+ return low + ( ( random() >> 8 ) % ( high + 1 - low ) );
+
+ return low + ( random() % ( high + 1 - low ) );
+ }
+
+
+ static int
+ copyfont( struct fontlist* item,
+ char* newfont )
+ {
+ static char buffer[8096];
+ FILE *good, *newf;
+ size_t len;
+ unsigned int i, err_cnt;
+
+
+ good = fopen( item->name, "r" );
+ if ( !good )
+ {
+ fprintf( stderr, "Can't open `%s'\n", item->name );
+ return false;
+ }
+
+ newf = fopen( newfont, "w+" );
+ if ( !newf )
+ {
+ fprintf( stderr, "Can't create temporary output file `%s'\n",
+ newfont );
+ exit( 1 );
+ }
+
+ while ( ( len = fread( buffer, 1, sizeof ( buffer ), good ) ) > 0 )
+ fwrite( buffer, 1, len, newf );
+
+ fclose( good );
+
+ err_cnt = getErrorCnt( item );
+ for ( i = 0; i < err_cnt; i++ )
+ {
+ fseek( newf, getRandom( 0, (int)( item->len - 1 ) ), SEEK_SET );
+
+ if ( item->isbinary )
+ putc( getRandom( 0, 0xFF ), newf );
+ else if ( item->isascii )
+ putc( getRandom( 0x20, 0x7E ), newf );
+ else
+ {
+ int hex = getRandom( 0, 15 );
+
+
+ if ( hex < 10 )
+ hex += '0';
+ else
+ hex += 'A' - 10;
+
+ putc( hex, newf );
+ }
+ }
+
+ if ( ferror( newf ) )
+ {
+ fclose( newf );
+ unlink( newfont );
+ return false;
+ }
+
+ fclose( newf );
+
+ return true;
+ }
+
+
+ static int child_pid;
+
+ static void
+ abort_test( int sig )
+ {
+ FT_UNUSED( sig );
+
+ /* If a time-out happens, then kill the child */
+ kill( child_pid, SIGFPE );
+ write( 2, "Timeout... ", 11 );
+ }
+
+
+ static void
+ do_test( void )
+ {
+ int i = getRandom( 0, (int)( fcnt - 1 ) );
+ static int test_num = 0;
+ char buffer[1024];
+
+
+ sprintf( buffer, "%s/test%d", results_dir, test_num++ );
+
+ if ( copyfont ( &fontlist[i], buffer ) )
+ {
+ signal( SIGALRM, abort_test );
+ /* Anything that takes more than 20 seconds */
+ /* to parse and/or rasterize is an error. */
+ alarm( 20 );
+ if ( ( child_pid = fork() ) == 0 )
+ ExecuteTest( buffer );
+ else if ( child_pid != -1 )
+ {
+ int status;
+
+
+ waitpid( child_pid, &status, 0 );
+ alarm( 0 );
+ if ( WIFSIGNALED ( status ) )
+ printf( "Error found in file `%s'\n", buffer );
+ else
+ unlink( buffer );
+ }
+ else
+ {
+ fprintf( stderr, "Can't fork test case.\n" );
+ exit( 1 );
+ }
+ alarm( 0 );
+ }
+ }
+
+
+ static void
+ usage( FILE* out,
+ char* name )
+ {
+ char** d = default_dir_list;
+ char** e = default_ext_list;
+
+
+ fprintf( out, "%s [options] -- Generate random erroneous fonts\n"
+ " and attempt to parse them with FreeType.\n\n", name );
+
+ fprintf( out, " --all All non-directory files are assumed to be fonts.\n" );
+ fprintf( out, " --check-outlines Make sure we can parse the outlines of each glyph.\n" );
+ fprintf( out, " --dir <path> Append <path> to list of font search directories\n"
+ " (no recursive search).\n" );
+ fprintf( out, " --error-count <cnt> Introduce <cnt> single byte errors into each font\n"
+ " (default: 1)\n" );
+ fprintf( out, " --error-fraction <frac> Introduce <frac>*filesize single byte errors\n"
+ " into each font (default: 0.0).\n" );
+ fprintf( out, " --ext <ext> Add <ext> to list of extensions indicating fonts.\n" );
+ fprintf( out, " --help Print this.\n" );
+ fprintf( out, " --nohints Turn off hinting.\n" );
+ fprintf( out, " --rasterize Attempt to rasterize each glyph.\n" );
+ fprintf( out, " --results <path> Place the created test fonts into <path>\n"
+ " (default: `results')\n" );
+ fprintf( out, " --size <float> Use the given font size for the tests.\n" );
+ fprintf( out, " --test <file> Run a single test on an already existing file.\n" );
+ fprintf( out, "\n" );
+
+ fprintf( out, "Default font extensions:\n" );
+ fprintf( out, " " );
+ while ( *e )
+ fprintf( out, " .%s", *e++ );
+ fprintf( out, "\n" );
+
+ fprintf( out, "Default font directories:\n" );
+ fprintf( out, " " );
+ while ( *d )
+ fprintf( out, " %s", *d++ );
+ fprintf( out, "\n" );
+ }
+
+
+ int
+ main( int argc,
+ char** argv )
+ {
+ char **dirs, **exts;
+ int dcnt = 0, ecnt = 0, rset = false, allexts = false;
+ int i;
+ time_t now;
+ char* testfile = NULL;
+
+
+ dirs = calloc( (size_t)( argc + 1 ), sizeof ( char ** ) );
+ exts = calloc( (size_t)( argc + 1 ), sizeof ( char ** ) );
+
+ for ( i = 1; i < argc; i++ )
+ {
+ char* pt = argv[i];
+ char* end;
+
+
+ if ( pt[0] == '-' && pt[1] == '-' )
+ pt++;
+
+ if ( strcmp( pt, "-all" ) == 0 )
+ allexts = true;
+ else if ( strcmp( pt, "-check-outlines" ) == 0 )
+ check_outlines = true;
+ else if ( strcmp( pt, "-dir" ) == 0 )
+ dirs[dcnt++] = argv[++i];
+ else if ( strcmp( pt, "-error-count" ) == 0 )
+ {
+ if ( !rset )
+ error_fraction = 0.0;
+ rset = true;
+ error_count = (unsigned int)strtoul( argv[++i], &end, 10 );
+ if ( *end != '\0' )
+ {
+ fprintf( stderr, "Bad value for error-count: %s\n", argv[i] );
+ exit( 1 );
+ }
+ }
+ else if ( strcmp( pt, "-error-fraction" ) == 0 )
+ {
+ if ( !rset )
+ error_count = 0;
+ rset = true;
+ error_fraction = strtod( argv[++i], &end );
+ if ( *end != '\0' )
+ {
+ fprintf( stderr, "Bad value for error-fraction: %s\n", argv[i] );
+ exit( 1 );
+ }
+ if ( error_fraction < 0.0 || error_fraction > 1.0 )
+ {
+ fprintf( stderr, "error-fraction must be in the range [0;1]\n" );
+ exit( 1 );
+ }
+ }
+ else if ( strcmp( pt, "-ext" ) == 0 )
+ exts[ecnt++] = argv[++i];
+ else if ( strcmp( pt, "-help" ) == 0 )
+ {
+ usage( stdout, argv[0] );
+ exit( 0 );
+ }
+ else if ( strcmp( pt, "-nohints" ) == 0 )
+ nohints = true;
+ else if ( strcmp( pt, "-rasterize" ) == 0 )
+ rasterize = true;
+ else if ( strcmp( pt, "-results" ) == 0 )
+ results_dir = argv[++i];
+ else if ( strcmp( pt, "-size" ) == 0 )
+ {
+ font_size = (FT_F26Dot6)( strtod( argv[++i], &end ) * 64 );
+ if ( *end != '\0' || font_size < 64 )
+ {
+ fprintf( stderr, "Bad value for size: %s\n", argv[i] );
+ exit( 1 );
+ }
+ }
+ else if ( strcmp( pt, "-test" ) == 0 )
+ testfile = argv[++i];
+ else
+ {
+ usage( stderr, argv[0] );
+ exit( 1 );
+ }
+ }
+
+ if ( allexts )
+ {
+ free( exts );
+ exts = NULL;
+ }
+ else if ( ecnt == 0 )
+ {
+ free( exts );
+ exts = default_ext_list;
+ }
+
+ if ( dcnt == 0 )
+ {
+ free( dirs );
+ dirs = default_dir_list;
+ }
+
+ if ( testfile )
+ ExecuteTest( testfile ); /* This should never return */
+
+ time( &now );
+ srandom( (unsigned int)now );
+
+ FindFonts( dirs, exts );
+ mkdir( results_dir, 0755 );
+
+ forever
+ do_test();
+
+ return 0;
+ }
+
+
+/* EOF */
diff --git a/src/third_party/freetype2/src/tools/no-copyright b/src/third_party/freetype2/src/tools/no-copyright
new file mode 100644
index 0000000..d639aa4
--- /dev/null
+++ b/src/third_party/freetype2/src/tools/no-copyright
@@ -0,0 +1,65 @@
+# Files that don't get a copyright, or which are taken from elsewhere.
+#
+# All lines in this file are patterns, including the comment lines; this
+# means that e.g. `FTL.TXT' matches all files that have this string in
+# the file name (including the path relative to the current directory,
+# always starting with `./').
+#
+# Don't put empty lines into this file!
+#
+.gitignore
+#
+builds/unix/pkg.m4
+#
+docs/FTL.TXT
+docs/GPLv2.TXT
+#
+include/freetype/internal/fthash.h
+#
+src/base/fthash.c
+src/base/md5.c
+src/base/md5.h
+#
+src/bdf/bdf.c
+src/bdf/bdf.h
+src/bdf/bdfdrivr.c
+src/bdf/bdfdrivr.h
+src/bdf/bdferror.h
+src/bdf/bdflib.c
+src/bdf/module.mk
+src/bdf/README
+src/bdf/rules.mk
+#
+src/pcf/module.mk
+src/pcf/pcf.c
+src/pcf/pcf.h
+src/pcf/pcfdrivr.c
+src/pcf/pcfdrivr.h
+src/pcf/pcferror.h
+src/pcf/pcfread.c
+src/pcf/pcfread.h
+src/pcf/pcfutil.c
+src/pcf/pcfutil.h
+src/pcf/README
+src/pcf/rules.mk
+#
+src/gzip/adler32.c
+src/gzip/infblock.c
+src/gzip/infblock.h
+src/gzip/infcodes.c
+src/gzip/infcodes.h
+src/gzip/inffixed.h
+src/gzip/inflate.c
+src/gzip/inftrees.c
+src/gzip/inftrees.h
+src/gzip/infutil.c
+src/gzip/infutil.h
+src/gzip/zconf.h
+src/gzip/zlib.h
+src/gzip/zutil.c
+src/gzip/zutil.h
+#
+src/tools/apinames.c
+src/tools/ftrandom/ftrandom.c
+#
+# EOF
diff --git a/src/third_party/freetype2/src/tools/test_afm.c b/src/third_party/freetype2/src/tools/test_afm.c
new file mode 100644
index 0000000..8de619b
--- /dev/null
+++ b/src/third_party/freetype2/src/tools/test_afm.c
@@ -0,0 +1,157 @@
+/*
+ * gcc -DFT2_BUILD_LIBRARY -I../../include -o test_afm test_afm.c \
+ * -L../../objs/.libs -lfreetype -lz -static
+ */
+#include <ft2build.h>
+#include FT_FREETYPE_H
+#include FT_INTERNAL_STREAM_H
+#include FT_INTERNAL_POSTSCRIPT_AUX_H
+
+ void dump_fontinfo( AFM_FontInfo fi )
+ {
+ FT_UInt i;
+
+
+ printf( "This AFM is for %sCID font.\n\n",
+ ( fi->IsCIDFont ) ? "" : "non-" );
+
+ printf( "FontBBox: %.2f %.2f %.2f %.2f\n", fi->FontBBox.xMin / 65536.,
+ fi->FontBBox.yMin / 65536.,
+ fi->FontBBox.xMax / 65536.,
+ fi->FontBBox.yMax / 65536. );
+ printf( "Ascender: %.2f\n", fi->Ascender / 65536. );
+ printf( "Descender: %.2f\n\n", fi->Descender / 65536. );
+
+ if ( fi->NumTrackKern )
+ printf( "There are %d sets of track kernings:\n",
+ fi->NumTrackKern );
+ else
+ printf( "There is no track kerning.\n" );
+
+ for ( i = 0; i < fi->NumTrackKern; i++ )
+ {
+ AFM_TrackKern tk = fi->TrackKerns + i;
+
+
+ printf( "\t%2d: %5.2f %5.2f %5.2f %5.2f\n", tk->degree,
+ tk->min_ptsize / 65536.,
+ tk->min_kern / 65536.,
+ tk->max_ptsize / 65536.,
+ tk->max_kern / 65536. );
+ }
+
+ printf( "\n" );
+
+ if ( fi->NumKernPair )
+ printf( "There are %d kerning pairs:\n",
+ fi->NumKernPair );
+ else
+ printf( "There is no kerning pair.\n" );
+
+ for ( i = 0; i < fi->NumKernPair; i++ )
+ {
+ AFM_KernPair kp = fi->KernPairs + i;
+
+
+ printf( "\t%3d + %3d => (%4d, %4d)\n", kp->index1,
+ kp->index2,
+ kp->x,
+ kp->y );
+ }
+
+ }
+
+ int
+ dummy_get_index( const char* name,
+ FT_Offset len,
+ void* user_data )
+ {
+ if ( len )
+ return name[0];
+ else
+ return 0;
+ }
+
+ FT_Error
+ parse_afm( FT_Library library,
+ FT_Stream stream,
+ AFM_FontInfo fi )
+ {
+ PSAux_Service psaux;
+ AFM_ParserRec parser;
+ FT_Error error = FT_Err_Ok;
+
+
+ psaux = (PSAux_Service)FT_Get_Module_Interface( library, "psaux" );
+ if ( !psaux || !psaux->afm_parser_funcs )
+ return -1;
+
+ error = FT_Stream_EnterFrame( stream, stream->size );
+ if ( error )
+ return error;
+
+ error = psaux->afm_parser_funcs->init( &parser,
+ library->memory,
+ stream->cursor,
+ stream->limit );
+ if ( error )
+ return error;
+
+ parser.FontInfo = fi;
+ parser.get_index = dummy_get_index;
+
+ error = psaux->afm_parser_funcs->parse( &parser );
+
+ psaux->afm_parser_funcs->done( &parser );
+
+ return error;
+ }
+
+
+ int main( int argc,
+ char** argv )
+ {
+ FT_Library library;
+ FT_StreamRec stream;
+ FT_Error error = FT_Err_Ok;
+ AFM_FontInfoRec fi;
+
+
+ if ( argc < 2 )
+ return FT_ERR( Invalid_Argument );
+
+ error = FT_Init_FreeType( &library );
+ if ( error )
+ return error;
+
+ FT_ZERO( &stream );
+ error = FT_Stream_Open( &stream, argv[1] );
+ if ( error )
+ goto Exit;
+ stream.memory = library->memory;
+
+ FT_ZERO( &fi );
+ error = parse_afm( library, &stream, &fi );
+
+ if ( !error )
+ {
+ FT_Memory memory = library->memory;
+
+
+ dump_fontinfo( &fi );
+
+ if ( fi.KernPairs )
+ FT_FREE( fi.KernPairs );
+ if ( fi.TrackKerns )
+ FT_FREE( fi.TrackKerns );
+ }
+ else
+ printf( "parse error\n" );
+
+ FT_Stream_Close( &stream );
+
+ Exit:
+ FT_Done_FreeType( library );
+
+ return error;
+ }
diff --git a/src/third_party/freetype2/src/tools/test_bbox.c b/src/third_party/freetype2/src/tools/test_bbox.c
new file mode 100644
index 0000000..64b82c3
--- /dev/null
+++ b/src/third_party/freetype2/src/tools/test_bbox.c
@@ -0,0 +1,188 @@
+#include <ft2build.h>
+#include FT_FREETYPE_H
+#include FT_BBOX_H
+
+
+#include <time.h> /* for clock() */
+
+/* SunOS 4.1.* does not define CLOCKS_PER_SEC, so include <sys/param.h> */
+/* to get the HZ macro which is the equivalent. */
+#if defined(__sun__) && !defined(SVR4) && !defined(__SVR4)
+#include <sys/param.h>
+#define CLOCKS_PER_SEC HZ
+#endif
+
+ static long
+ get_time( void )
+ {
+ return clock() * 10000L / CLOCKS_PER_SEC;
+ }
+
+
+
+
+ /* test bbox computations */
+
+#define XSCALE 65536
+#define XX(x) ((FT_Pos)(x*XSCALE))
+#define XVEC(x,y) { XX(x), XX(y) }
+#define XVAL(x) ((x)/(1.0*XSCALE))
+
+ /* dummy outline #1 */
+ static FT_Vector dummy_vec_1[4] =
+ {
+#if 1
+ XVEC( 408.9111, 535.3164 ),
+ XVEC( 455.8887, 634.396 ),
+ XVEC( -37.8765, 786.2207 ),
+ XVEC( 164.6074, 535.3164 )
+#else
+ { (FT_Int32)0x0198E93DL , (FT_Int32)0x021750FFL }, /* 408.9111, 535.3164 */
+ { (FT_Int32)0x01C7E312L , (FT_Int32)0x027A6560L }, /* 455.8887, 634.3960 */
+ { (FT_Int32)0xFFDA1F9EL , (FT_Int32)0x0312387FL }, /* -37.8765, 786.2207 */
+ { (FT_Int32)0x00A49B7EL , (FT_Int32)0x021750FFL } /* 164.6074, 535.3164 */
+#endif
+ };
+
+ static char dummy_tag_1[4] =
+ {
+ FT_CURVE_TAG_ON,
+ FT_CURVE_TAG_CUBIC,
+ FT_CURVE_TAG_CUBIC,
+ FT_CURVE_TAG_ON
+ };
+
+ static short dummy_contour_1[1] =
+ {
+ 3
+ };
+
+ static FT_Outline dummy_outline_1 =
+ {
+ 1,
+ 4,
+ dummy_vec_1,
+ dummy_tag_1,
+ dummy_contour_1,
+ 0
+ };
+
+
+ /* dummy outline #2 */
+ static FT_Vector dummy_vec_2[4] =
+ {
+ XVEC( 100.0, 100.0 ),
+ XVEC( 100.0, 200.0 ),
+ XVEC( 200.0, 200.0 ),
+ XVEC( 200.0, 133.0 )
+ };
+
+ static FT_Outline dummy_outline_2 =
+ {
+ 1,
+ 4,
+ dummy_vec_2,
+ dummy_tag_1,
+ dummy_contour_1,
+ 0
+ };
+
+
+ /* dummy outline #3 with bbox of [0 100 128 128] precisely */
+ static FT_Vector dummy_vec_3[4] =
+ {
+ XVEC( 100.0, 127.0 ),
+ XVEC( 200.0, 127.0 ),
+ XVEC( 0.0, 136.0 ),
+ XVEC( 0.0, 100.0 )
+ };
+
+ static FT_Outline dummy_outline_3 =
+ {
+ 1,
+ 4,
+ dummy_vec_3,
+ dummy_tag_1,
+ dummy_contour_1,
+ 0
+ };
+
+
+ static void
+ dump_outline( FT_Outline* outline )
+ {
+ FT_BBox bbox;
+
+ /* compute and display cbox */
+ FT_Outline_Get_CBox( outline, &bbox );
+ printf( "cbox = [%.2f %.2f %.2f %.2f]\n",
+ XVAL( bbox.xMin ),
+ XVAL( bbox.yMin ),
+ XVAL( bbox.xMax ),
+ XVAL( bbox.yMax ) );
+
+ /* compute and display bbox */
+ FT_Outline_Get_BBox( outline, &bbox );
+ printf( "bbox = [%.2f %.2f %.2f %.2f]\n",
+ XVAL( bbox.xMin ),
+ XVAL( bbox.yMin ),
+ XVAL( bbox.xMax ),
+ XVAL( bbox.yMax ) );
+ }
+
+
+
+ static void
+ profile_outline( FT_Outline* outline,
+ long repeat )
+ {
+ FT_BBox bbox;
+ long count;
+ long time0;
+
+ time0 = get_time();
+ for ( count = repeat; count > 0; count-- )
+ FT_Outline_Get_CBox( outline, &bbox );
+
+ time0 = get_time() - time0;
+ printf( "time = %6.3f cbox = [%8.4f %8.4f %8.4f %8.4f]\n",
+ ((double)time0/10000.0),
+ XVAL( bbox.xMin ),
+ XVAL( bbox.yMin ),
+ XVAL( bbox.xMax ),
+ XVAL( bbox.yMax ) );
+ printf( "cbox_hex = [%08X %08X %08X %08X]\n",
+ bbox.xMin, bbox.yMin, bbox.xMax, bbox.yMax );
+
+
+ time0 = get_time();
+ for ( count = repeat; count > 0; count-- )
+ FT_Outline_Get_BBox( outline, &bbox );
+
+ time0 = get_time() - time0;
+ printf( "time = %6.3f bbox = [%8.4f %8.4f %8.4f %8.4f]\n",
+ ((double)time0/10000.0),
+ XVAL( bbox.xMin ),
+ XVAL( bbox.yMin ),
+ XVAL( bbox.xMax ),
+ XVAL( bbox.yMax ) );
+ printf( "bbox_hex = [%08X %08X %08X %08X]\n",
+ bbox.xMin, bbox.yMin, bbox.xMax, bbox.yMax );
+ }
+
+#define REPEAT 1000000L
+
+ int main( int argc, char** argv )
+ {
+ printf( "outline #1\n" );
+ profile_outline( &dummy_outline_1, REPEAT );
+
+ printf( "outline #2\n" );
+ profile_outline( &dummy_outline_2, REPEAT );
+
+ printf( "outline #3\n" );
+ profile_outline( &dummy_outline_3, REPEAT );
+
+ return 0;
+ }
+
diff --git a/src/third_party/freetype2/src/tools/test_trig.c b/src/third_party/freetype2/src/tools/test_trig.c
new file mode 100644
index 0000000..99ac1cf
--- /dev/null
+++ b/src/third_party/freetype2/src/tools/test_trig.c
@@ -0,0 +1,258 @@
+#include <ft2build.h>
+#include FT_FREETYPE_H
+#include FT_TRIGONOMETRY_H
+
+#include <math.h>
+#include <stdio.h>
+
+#define PI 3.14159265358979323846
+#define SPI (PI/FT_ANGLE_PI)
+
+/* the precision in 16.16 fixed-point checks. Expect between 2 and 5 */
+/* noise LSB bits during operations, due to rounding errors.. */
+#define THRESHOLD 64
+
+ static error = 0;
+
+ static void
+ test_cos( void )
+ {
+ int i;
+
+
+ for ( i = 0; i < FT_ANGLE_2PI; i += 0x10000L )
+ {
+ FT_Fixed f1, f2;
+ double d2;
+
+
+ f1 = FT_Cos(i);
+ d2 = cos( i*SPI );
+ f2 = (FT_Fixed)(d2*65536.0);
+
+ if ( abs( f2-f1 ) > THRESHOLD )
+ {
+ error = 1;
+ printf( "FT_Cos[%3d] = %.7f cos[%3d] = %.7f\n",
+ (i >> 16), f1/65536.0, (i >> 16), d2 );
+ }
+ }
+ }
+
+
+ static void
+ test_sin( void )
+ {
+ int i;
+
+
+ for ( i = 0; i < FT_ANGLE_2PI; i += 0x10000L )
+ {
+ FT_Fixed f1, f2;
+ double d2;
+
+
+ f1 = FT_Sin(i);
+ d2 = sin( i*SPI );
+ f2 = (FT_Fixed)(d2*65536.0);
+
+ if ( abs( f2-f1 ) > THRESHOLD )
+ {
+ error = 1;
+ printf( "FT_Sin[%3d] = %.7f sin[%3d] = %.7f\n",
+ (i >> 16), f1/65536.0, (i >> 16), d2 );
+ }
+ }
+ }
+
+
+ static void
+ test_tan( void )
+ {
+ int i;
+
+
+ for ( i = 0; i < FT_ANGLE_PI2 - 0x2000000L; i += 0x10000L )
+ {
+ FT_Fixed f1, f2;
+ double d2;
+
+
+ f1 = FT_Tan(i);
+ d2 = tan( i*SPI );
+ f2 = (FT_Fixed)(d2*65536.0);
+
+ if ( abs( f2-f1 ) > THRESHOLD )
+ {
+ error = 1;
+ printf( "FT_Tan[%3d] = %.7f tan[%3d] = %.7f\n",
+ (i >> 16), f1/65536.0, (i >> 16), d2 );
+ }
+ }
+ }
+
+
+ static void
+ test_atan2( void )
+ {
+ int i;
+
+
+ for ( i = 0; i < FT_ANGLE_2PI; i += 0x10000L )
+ {
+ FT_Fixed c2, s2;
+ double l, a, c1, s1;
+ int j;
+
+
+ l = 5.0;
+ a = i*SPI;
+
+ c1 = l * cos(a);
+ s1 = l * sin(a);
+
+ c2 = (FT_Fixed)(c1*65536.0);
+ s2 = (FT_Fixed)(s1*65536.0);
+
+ j = FT_Atan2( c2, s2 );
+ if ( j < 0 )
+ j += FT_ANGLE_2PI;
+
+ if ( abs( i - j ) > 1 )
+ {
+ printf( "FT_Atan2( %.7f, %.7f ) = %.5f, atan = %.5f\n",
+ c2/65536.0, s2/65536.0, j/65536.0, i/65536.0 );
+ }
+ }
+ }
+
+
+ static void
+ test_unit( void )
+ {
+ int i;
+
+
+ for ( i = 0; i < FT_ANGLE_2PI; i += 0x10000L )
+ {
+ FT_Vector v;
+ double a, c1, s1;
+ FT_Fixed c2, s2;
+
+
+ FT_Vector_Unit( &v, i );
+ a = ( i*SPI );
+ c1 = cos(a);
+ s1 = sin(a);
+ c2 = (FT_Fixed)(c1*65536.0);
+ s2 = (FT_Fixed)(s1*65536.0);
+
+ if ( abs( v.x-c2 ) > THRESHOLD ||
+ abs( v.y-s2 ) > THRESHOLD )
+ {
+ error = 1;
+ printf( "FT_Vector_Unit[%3d] = ( %.7f, %.7f ) vec = ( %.7f, %.7f )\n",
+ (i >> 16),
+ v.x/65536.0, v.y/65536.0,
+ c1, s1 );
+ }
+ }
+ }
+
+
+ static void
+ test_length( void )
+ {
+ int i;
+
+
+ for ( i = 0; i < FT_ANGLE_2PI; i += 0x10000L )
+ {
+ FT_Vector v;
+ FT_Fixed l, l2;
+
+
+ l = (FT_Fixed)(500.0*65536.0);
+ v.x = (FT_Fixed)( l * cos( i*SPI ) );
+ v.y = (FT_Fixed)( l * sin( i*SPI ) );
+ l2 = FT_Vector_Length( &v );
+
+ if ( abs( l2-l ) > THRESHOLD )
+ {
+ error = 1;
+ printf( "FT_Length( %.7f, %.7f ) = %.5f, length = %.5f\n",
+ v.x/65536.0, v.y/65536.0, l2/65536.0, l/65536.0 );
+ }
+ }
+ }
+
+
+ static void
+ test_rotate( void )
+ {
+ int rotate;
+
+
+ for ( rotate = 0; rotate < FT_ANGLE_2PI; rotate += 0x10000L )
+ {
+ double ra, cra, sra;
+ int i;
+
+
+ ra = rotate*SPI;
+ cra = cos( ra );
+ sra = sin( ra );
+
+ for ( i = 0; i < FT_ANGLE_2PI; i += 0x10000L )
+ {
+ FT_Fixed c2, s2, c4, s4;
+ FT_Vector v;
+ double l, a, c1, s1, c3, s3;
+
+
+ l = 500.0;
+ a = i*SPI;
+
+ c1 = l * cos(a);
+ s1 = l * sin(a);
+
+ v.x = c2 = (FT_Fixed)(c1*65536.0);
+ v.y = s2 = (FT_Fixed)(s1*65536.0);
+
+ FT_Vector_Rotate( &v, rotate );
+
+ c3 = c1 * cra - s1 * sra;
+ s3 = c1 * sra + s1 * cra;
+
+ c4 = (FT_Fixed)(c3*65536.0);
+ s4 = (FT_Fixed)(s3*65536.0);
+
+ if ( abs( c4 - v.x ) > THRESHOLD ||
+ abs( s4 - v.y ) > THRESHOLD )
+ {
+ error = 1;
+ printf( "FT_Rotate( (%.7f,%.7f), %.5f ) = ( %.7f, %.7f ), rot = ( %.7f, %.7f )\n",
+ c1, s1, ra,
+ c2/65536.0, s2/65536.0,
+ c4/65536.0, s4/65536.0 );
+ }
+ }
+ }
+ }
+
+
+ int main( void )
+ {
+ test_cos();
+ test_sin();
+ test_tan();
+ test_atan2();
+ test_unit();
+ test_length();
+ test_rotate();
+
+ if (!error)
+ printf( "trigonometry test ok !\n" );
+
+ return !error;
+ }
diff --git a/src/third_party/freetype2/src/tools/update-copyright b/src/third_party/freetype2/src/tools/update-copyright
new file mode 100755
index 0000000..4a8bf9b
--- /dev/null
+++ b/src/third_party/freetype2/src/tools/update-copyright
@@ -0,0 +1,14 @@
+#!/bin/sh
+
+# Run the `update-copyright-year' script on all files in the git repository,
+# taking care of exceptions stored in file `no-copyright'.
+
+topdir=`git rev-parse --show-toplevel`
+toolsdir=$topdir/src/tools
+
+git ls-files --full-name $topdir \
+| sed 's|^|../../|' \
+| grep -vFf $toolsdir/no-copyright \
+| xargs $toolsdir/update-copyright-year
+
+# EOF
diff --git a/src/third_party/freetype2/src/tools/update-copyright-year b/src/third_party/freetype2/src/tools/update-copyright-year
new file mode 100755
index 0000000..c659bba
--- /dev/null
+++ b/src/third_party/freetype2/src/tools/update-copyright-year
@@ -0,0 +1,138 @@
+eval '(exit $?0)' && eval 'exec perl -wS -i "$0" ${1+"$@"}'
+ & eval 'exec perl -wS -i "$0" $argv:q'
+ if 0;
+
+# Copyright (C) 2015-2020 by
+# Werner Lemberg.
+#
+# This file is part of the FreeType project, and may only be used, modified,
+# and distributed under the terms of the FreeType project license,
+# LICENSE.TXT. By continuing to use, modify, or distribute this file you
+# indicate that you have read the license and understand and accept it
+# fully.
+
+# [Note: This script is expected to be called by the shell, which in turn
+# calls perl automatically. The nifty start-up code above is based on
+# gnulib's `update-copyright' script; it is a more portable replacement for
+# the shebang, using the first `perl' program in the shell's path instead.]
+
+# Usage:
+#
+# update-copyright-year file1 [file2 ...]
+
+
+# This script handles copyright entries like
+#
+# Copyright 2000 by
+# foobar
+#
+# or
+#
+# /* Copyright 2000, 2001, 2004-2007 by */
+# /* foobar */
+#
+# and replaces them uniformly with
+#
+# Copyright 2000-2015
+# foobar
+#
+# and
+#
+# /* Copyright 2000-2015 by */
+# /* foobar */
+#
+# (assuming that the current year is 2015). As can be seen, the line length
+# is retained if there is non-whitespace after the word `by' on the same
+# line.
+
+use strict;
+
+
+my (undef, undef, undef,
+ undef, undef, $year,
+ undef, undef, undef) = localtime(time);
+$year += 1900;
+
+my $replaced = 0;
+
+
+# Loop over all input files; option `-i' (issued at the very beginning of
+# this script) makes perl edit them in-place.
+while (<>)
+{
+ # Only handle the first copyright notice in a file.
+ if (!$replaced)
+ {
+ # First try: Search multiple copyright years.
+ s {
+ (?<begin>.*)
+ Copyright
+ (?<space1>(\ +
+ | \ +\(C\)\ +))
+ (?<first>[12][0-9][0-9][0-9])
+ (?<middle>.+)
+ (?<last>[12][0-9][0-9][0-9])
+ (?<space2>\ +)
+ by
+ (?<space3>\ *)
+ (?<end>.*)
+ }
+ {
+ # Fill line to the same length (if appropriate); we skip the middle
+ # part but insert `(C)', three spaces, and `-'.
+ my $space = length($+{space1}) - 1
+ + length($+{middle}) - 1
+ + length($+{space2}) - 1
+ + length($+{space3})
+ - (length("(C)") + 1);
+
+ print "$+{begin}";
+ print "Copyright\ (C)\ $+{first}-$year\ by";
+ print ' ' x $space if length($+{end});
+ print "$+{end}\n";
+ $replaced = 1;
+ }ex
+ ||
+ # Second try: Search a single copyright year.
+ s {
+ (?<begin>.*)
+ Copyright
+ (?<space1>(\ +
+ | \ +\(C\)\ +))
+ (?<first>[12][0-9][0-9][0-9])
+ (?<space2>\ +)
+ by
+ (?<space3>\ *)
+ (?<end>.*)
+ }
+ {
+ # Fill line to the same length (if appropriate); we insert three
+ # spaces, a `-', and the current year.
+ my $space = length($+{space1}) - 1
+ + length($+{space2}) - 1
+ + length($+{space3})
+ - (length($year) + 1);
+
+ print "$+{begin}";
+ print "Copyright\ (C)\ $+{first}-$year\ by";
+ # If $space is negative this inserts nothing.
+ print ' ' x $space if length($+{end});
+ print "$+{end}\n";
+ $replaced = 1;
+ }ex
+ ||
+ # Otherwise print line unaltered.
+ print;
+ }
+ else
+ {
+ print;
+ }
+}
+continue
+{
+ # Reset $replaced before processing the next file.
+ $replaced = 0 if eof;
+}
+
+# EOF
diff --git a/src/third_party/libpng/libpng.gyp b/src/third_party/libpng/libpng.gyp
index 79153b2..ad2358c 100644
--- a/src/third_party/libpng/libpng.gyp
+++ b/src/third_party/libpng/libpng.gyp
@@ -137,9 +137,6 @@
'pngconf.h',
],
},
- 'includes': [
- '../../build/shim_headers.gypi',
- ],
},
],
}],
diff --git a/src/third_party/precommit-hooks/custom_hooks/check_copyright_year.py b/src/third_party/precommit-hooks/custom_hooks/check_copyright_year.py
index 0b4b516..692e44f 100755
--- a/src/third_party/precommit-hooks/custom_hooks/check_copyright_year.py
+++ b/src/third_party/precommit-hooks/custom_hooks/check_copyright_year.py
@@ -53,7 +53,7 @@
]
copyright_re = re.compile(r'Copyright (?P<created>\d{4})'
- r'(?P<current>-\d{4})? (?P<author>[\w\s]+)')
+ r'(-(?P<current>\d{4}))? (?P<author>[\w\s]+)')
current_year = datetime.datetime.today().year
for filename in filenames:
diff --git a/src/tools/__init__.py b/src/tools/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/src/tools/__init__.py
diff --git a/src/tools/download_from_gcs.py b/src/tools/download_from_gcs.py
new file mode 100755
index 0000000..85a93f7
--- /dev/null
+++ b/src/tools/download_from_gcs.py
@@ -0,0 +1,153 @@
+#!/usr/bin/env python
+# Copyright 2020 The Cobalt Authors. 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 argparse
+import hashlib
+import logging
+import os
+import shutil
+import ssl
+import stat
+import tempfile
+try:
+ import urllib.request as urllib
+except ImportError:
+ import urllib2 as urllib
+
+# ssl.SSLContext (and thus ssl.create_default_context) was introduced in
+# python 2.7.9. depot_tools provides python 2.7.6, so we wrap this import.
+try:
+ from ssl import create_default_context
+except ImportError:
+ create_default_context = lambda: None
+
+_BASE_GCS_URL = 'https://storage.googleapis.com'
+_BUFFER_SIZE = 2 * 1024 * 1024
+
+
+def AddExecutableBits(filename):
+ st = os.stat(filename)
+ os.chmod(filename, st.st_mode | stat.S_IXUSR | stat.S_IXGRP | stat.S_IXOTH)
+
+
+def ExtractSha1(filename):
+ with open(filename, 'rb') as f:
+ sha1 = hashlib.sha1()
+ buf = f.read(_BUFFER_SIZE)
+ while buf:
+ sha1.update(buf)
+ buf = f.read(_BUFFER_SIZE)
+ return sha1.hexdigest()
+
+
+def _DownloadFromGcsAndCheckSha1(bucket, sha1):
+ url = '{}/{}/{}'.format(_BASE_GCS_URL, bucket, sha1)
+ context = create_default_context()
+
+ res = urllib.urlopen(url, context=context) if context else urllib.urlopen(url)
+ if not res:
+ logging.error('Could not reach %s', url)
+ return None
+
+ with tempfile.NamedTemporaryFile(delete=False) as tmp_file:
+ shutil.copyfileobj(res, tmp_file)
+
+ if ExtractSha1(tmp_file.name) != sha1:
+ logging.error('Local and remote sha1s do not match. Skipping download.')
+ return None
+
+ return tmp_file
+
+
+def MaybeDownloadFileFromGcs(bucket, sha1_file, output_file, force=False):
+ """Download file from GCS if it doesn't already exist.
+
+ Args:
+ bucket: The GCS bucket that the file is stored in.
+ sha1_file: The file containing the sha1 of the file to download
+ output_file: The file to output to
+ force: If true, will overwrite an existing output_file
+ Returns:
+ True if it writes a file, False otherwise.
+ """
+ if not os.path.exists(sha1_file):
+ logging.error("Provided sha1 file %s doesn't exist", sha1_file)
+ with open(sha1_file) as fd:
+ sha1 = fd.read().strip()
+
+ if not force and os.path.exists(output_file):
+ with open(output_file, 'rb') as f:
+ if hashlib.sha1(f.read()).hexdigest() == sha1:
+ logging.info('%s exists and sha1s match, skipping download',
+ output_file)
+ return False
+
+ tmp_file = _DownloadFromGcsAndCheckSha1(bucket, sha1)
+ if not tmp_file:
+ return False
+
+ shutil.move(tmp_file.name, output_file)
+ AddExecutableBits(output_file)
+ return True
+
+
+def MaybeDownloadDirectoryFromGcs(bucket,
+ sha1_directory,
+ output_directory,
+ force=False):
+ res = True
+ for filename in os.listdir(sha1_directory):
+ filebase, ext = os.path.splitext(filename)
+ if ext == '.sha1':
+ filepath = os.path.join(sha1_directory, filename)
+ output_filepath = os.path.join(output_directory, filebase)
+ if not MaybeDownloadFileFromGcs(bucket, filepath, output_filepath, force):
+ res = False
+ return res
+
+
+if __name__ == "__main__":
+ logging_format = '[%(levelname)s:%(filename)s:%(lineno)s] %(message)s'
+ logging.basicConfig(
+ level=logging.INFO, format=logging_format, datefmt='%H:%M:%S')
+
+ parser = argparse.ArgumentParser()
+ parser.add_argument(
+ '-b',
+ '--bucket',
+ required=True,
+ help='GCS bucket the resource is located in.')
+ parser.add_argument(
+ '-s',
+ '--sha1',
+ required=True,
+ help='Path to file or directory containing sha1 checksum(s).')
+ parser.add_argument(
+ '-o',
+ '--output',
+ required=True,
+ help='Path to file or directory to download file(s) to.')
+ parser.add_argument(
+ '-f',
+ '--force',
+ action='store_true',
+ help='Replace an existing resource.')
+ args = parser.parse_args()
+
+ if os.path.isdir(args.sha1):
+ MaybeDownloadDirectoryFromGcs(args.bucket, args.sha1, args.output,
+ args.force)
+ else:
+ MaybeDownloadFileFromGcs(args.bucket, args.sha1, args.output, args.force)
diff --git a/src/tools/download_from_gcs_test.py b/src/tools/download_from_gcs_test.py
new file mode 100755
index 0000000..6abad17
--- /dev/null
+++ b/src/tools/download_from_gcs_test.py
@@ -0,0 +1,98 @@
+#!/usr/bin/env python
+# Copyright 2020 The Cobalt Authors. 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 argparse
+import hashlib
+import logging
+import os
+import sys
+import tempfile
+import unittest
+
+import tools.download_from_gcs as download_from_gcs
+
+_BUCKET = 'chromium-clang-format'
+_HASH_FILE_EXT = '.sha1'
+_TEST_PATH = os.path.join(
+ os.path.dirname(os.path.abspath(__file__)), 'testing/download_from_gcs')
+_TEST_DIRECTORY = 'test_dir'
+_TEST_FILE = 'clang-format.sha1'
+
+logging_format = '[%(levelname)s:%(filename)s:%(lineno)s] %(message)s'
+logging.basicConfig(
+ level=logging.INFO, format=logging_format, datefmt='%H:%M:%S')
+
+
+def _Sha1sMatch(file_to_read, file_to_hash):
+ if not os.path.exists(file_to_read):
+ logging.error('%s does not exist.', file_to_read)
+ return False
+
+ if not os.path.exists(file_to_hash):
+ logging.error('%s does not exist.', file_to_hash)
+ return False
+
+ with open(file_to_read) as f:
+ sha1 = f.read().strip()
+
+ return download_from_gcs.ExtractSha1(file_to_hash) == sha1
+
+
+class TestFileDownload(unittest.TestCase):
+
+ def setUp(self):
+ self.test_file = os.path.join(_TEST_PATH, _TEST_FILE)
+ self.output_file = tempfile.NamedTemporaryFile()
+ self.bucket = _BUCKET
+
+ def downloadFile(self, test_file, output_file):
+ return download_from_gcs.MaybeDownloadFileFromGcs(
+ self.bucket, sha1_file=test_file, output_file=output_file)
+
+ def testDownloadSingleFile(self):
+ self.assertTrue(self.downloadFile(self.test_file, self.output_file.name))
+ self.assertTrue(_Sha1sMatch(self.test_file, self.output_file.name))
+
+
+class DirectoryDownloadTest(unittest.TestCase):
+
+ def setUp(self):
+ self.test_directory = os.path.join(_TEST_PATH, _TEST_DIRECTORY)
+ self.output_directory = tempfile.TemporaryDirectory()
+ self.bucket = _BUCKET
+
+ def tearDown(self):
+ self.output_directory.cleanup()
+
+ def downloadFiles(self, test_directory, output_directory):
+ return download_from_gcs.MaybeDownloadDirectoryFromGcs(
+ self.bucket,
+ sha1_directory=test_directory,
+ output_directory=output_directory)
+
+ def testDownloadMultipleFiles(self):
+ self.assertTrue(
+ self.downloadFiles(self.test_directory, self.output_directory.name))
+
+ sha1_files = list(os.listdir(self.test_directory))
+ output_files = list(os.listdir(self.output_directory.name))
+ self.assertEqual(len(sha1_files), len(output_files))
+
+ for output_file in output_files:
+ sha1_file = output_file + _HASH_FILE_EXT
+ self.assertIn(sha1_file, sha1_files)
+
+ sha1_file = os.path.join(self.test_directory, sha1_file)
+ output_file = os.path.join(self.output_directory.name, output_file)
+ self.assertTrue(_Sha1sMatch(sha1_file, output_file))
diff --git a/src/tools/gyp/pylib/gyp/MSVSSettings.py b/src/tools/gyp/pylib/gyp/MSVSSettings.py
index d0d4990..8526389 100644
--- a/src/tools/gyp/pylib/gyp/MSVSSettings.py
+++ b/src/tools/gyp/pylib/gyp/MSVSSettings.py
@@ -532,7 +532,6 @@
_Same(_compile, 'ForcedUsingFiles', _file_list) # /FU
_Same(_compile, 'GenerateXMLDocumentationFiles', _boolean) # /doc
_Same(_compile, 'IgnoreStandardIncludePath', _boolean) # /X
-_Same(_compile, 'MinimalRebuild', _boolean) # /Gm
_Same(_compile, 'OmitDefaultLibName', _boolean) # /Zl
_Same(_compile, 'OmitFramePointers', _boolean) # /Oy
_Same(_compile, 'PreprocessorDefinitions', _string_list) # /D
diff --git a/src/tools/gyp/pylib/gyp/MSVSSettings_test.py b/src/tools/gyp/pylib/gyp/MSVSSettings_test.py
index 4e06da3..52ff7c3 100755
--- a/src/tools/gyp/pylib/gyp/MSVSSettings_test.py
+++ b/src/tools/gyp/pylib/gyp/MSVSSettings_test.py
@@ -79,7 +79,6 @@
'IgnoreStandardIncludePath': 'true',
'InlineFunctionExpansion': '1',
'KeepComments': 'true',
- 'MinimalRebuild': 'true',
'ObjectFile': 'a_file_name',
'OmitDefaultLibName': 'true',
'OmitFramePointers': 'true',
@@ -318,7 +317,6 @@
'IgnoreStandardIncludePath': 'true',
'InlineFunctionExpansion': 'OnlyExplicitInline',
'IntrinsicFunctions': 'false',
- 'MinimalRebuild': 'true',
'MultiProcessorCompilation': 'true',
'ObjectFileName': 'a_file_name',
'OmitDefaultLibName': 'true',
@@ -690,7 +688,6 @@
'IgnoreStandardIncludePath': 'true',
'InlineFunctionExpansion': '2',
'KeepComments': 'true',
- 'MinimalRebuild': 'true',
'ObjectFile': 'a_file_name',
'OmitDefaultLibName': 'true',
'OmitFramePointers': 'true',
diff --git a/src/tools/gyp/pylib/gyp/generator/ninja.py b/src/tools/gyp/pylib/gyp/generator/ninja.py
index 010fbe9..c3f4ec9 100755
--- a/src/tools/gyp/pylib/gyp/generator/ninja.py
+++ b/src/tools/gyp/pylib/gyp/generator/ninja.py
@@ -1,3 +1,4 @@
+#!/usr/bin/env python2
# Copyright (c) 2013 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.
@@ -77,7 +78,9 @@
is_windows = platform.system() == 'Windows'
microsoft_flavors = [
- 'win', 'win-win32', 'win-win32-lib',
+ 'win',
+ 'win-win32',
+ 'win-win32-lib',
]
sony_flavors = []
@@ -139,8 +142,7 @@
def GetGeneratorVariables(flavor):
generator_variables = copy.copy(generator_default_variables)
if GetToolchainOrNone(flavor):
- GetToolchainOrNone(
- flavor).SetAdditionalGypVariables(generator_variables)
+ GetToolchainOrNone(flavor).SetAdditionalGypVariables(generator_variables)
else:
CalculateVariables(generator_variables, {'flavor': flavor})
return generator_variables
@@ -778,8 +780,8 @@
inputs = [self.GypPathToNinja(i, env) for i in inputs]
outputs = [self.GypPathToNinja(o, env) for o in outputs]
- extra_bindings.append(('unique_name',
- hashlib.md5(outputs[0]).hexdigest()))
+ extra_bindings.append(
+ ('unique_name', hashlib.md5(outputs[0]).hexdigest()))
self.ninja.build(
outputs,
rule_name,
@@ -895,11 +897,11 @@
shell = GetShell(self.flavor)
if self.toolset == 'target':
- toolchain = GetTargetToolchain(self.flavor, spec=spec,
- config_name=config_name)
+ toolchain = GetTargetToolchain(
+ self.flavor, spec=spec, config_name=config_name)
else:
- toolchain = GetHostToolchain(self.flavor, spec=spec,
- config_name=config_name)
+ toolchain = GetHostToolchain(
+ self.flavor, spec=spec, config_name=config_name)
defines = config.get('defines', [])
include_dirs = [
@@ -1007,8 +1009,7 @@
gyp_path_to_ninja=self.GypPathToNinja,
expand_special=self.ExpandSpecial,
gyp_path_to_unique_output=self.GypPathToUniqueOutput,
- compute_output_file_name=self.ComputeOutputFileName
- )
+ compute_output_file_name=self.ComputeOutputFileName)
else:
toolchain = GetHostToolchain(
self.flavor,
@@ -1017,8 +1018,7 @@
gyp_path_to_ninja=self.GypPathToNinja,
expand_special=self.ExpandSpecial,
gyp_path_to_unique_output=self.GypPathToUniqueOutput,
- compute_output_file_name=self.ComputeOutputFileName
- )
+ compute_output_file_name=self.ComputeOutputFileName)
shell = GetShell(self.flavor)
extra_bindings = []
@@ -1039,8 +1039,8 @@
libraries = spec.get(libraries_keyword, []) + config.get(
libraries_keyword, [])
- ldflags_executable = GetConfigFlags(
- config, self.toolset, 'ldflags_executable')
+ ldflags_executable = GetConfigFlags(config, self.toolset,
+ 'ldflags_executable')
if not ldflags_executable:
ldflags_executable = GetConfigFlags(config, self.toolset, 'ldflags')
@@ -1051,8 +1051,8 @@
self.ninja.variable('{0}_flags'.format(rule_name),
shell.Join(executable_linker_flags))
elif target_type == 'shared_library':
- shared_library_linker = FindFirstInstanceOf(
- abstract.SharedLibraryLinker, toolchain)
+ shared_library_linker = FindFirstInstanceOf(abstract.SharedLibraryLinker,
+ toolchain)
assert shared_library_linker, (
'Toolchain must provide shared library linker '
'for {0} platform.').format(self.toolset)
@@ -1081,12 +1081,11 @@
extra_bindings.append(('soname', os.path.split(output)[1]))
extra_bindings.append(('dll', output))
if '/NOENTRY' not in shared_library_linker_flags:
- extra_bindings.append(('implibflag',
- '/IMPLIB:%s' % output + '.lib'))
+ extra_bindings.append(('implibflag', '/IMPLIB:%s' % output + '.lib'))
else:
- raise Exception('Target type {0} is not supported for target {1}.'
- .format(target_type, spec['target_name']))
+ raise Exception('Target type {0} is not supported for target {1}.'.format(
+ target_type, spec['target_name']))
order_only_deps = set()
@@ -1146,15 +1145,13 @@
self.flavor,
spec=spec,
config_name=config_name,
- gyp_path_to_ninja=self.GypPathToNinja
- )
+ gyp_path_to_ninja=self.GypPathToNinja)
else:
toolchain = GetHostToolchain(
self.flavor,
spec=spec,
config_name=config_name,
- gyp_path_to_ninja=self.GypPathToNinja
- )
+ gyp_path_to_ninja=self.GypPathToNinja)
shell = GetShell(self.flavor)
static_linker = FindFirstInstanceOf(abstract.StaticLinker, toolchain)
@@ -1510,8 +1507,8 @@
default_variables.setdefault('SHARED_LIB_SUFFIX', '.so')
default_variables.setdefault('SHARED_LIB_DIR',
os.path.join('$!PRODUCT_DIR', 'lib'))
- default_variables.setdefault('LIB_DIR', os.path.join(
- '$!PRODUCT_DIR', 'obj'))
+ default_variables.setdefault('LIB_DIR',
+ os.path.join('$!PRODUCT_DIR', 'obj'))
def ComputeOutputDir(params):
@@ -1549,6 +1546,7 @@
pass
return open(path, mode)
+
def MaybeWritePathVariable(ninja, tool, toolset):
if tool.GetPath():
ninja.variable('{0}_path'.format(GetNinjaRuleName(tool, toolset)),
@@ -1653,9 +1651,22 @@
toplevel_build, generator_flags, OpenOutput)
else:
gyp.msvs_emulation.GenerateEnvironmentFiles(toplevel_build,
- generator_flags, OpenOutput)
- master_ninja.variable('python', sys.executable)
- master_ninja.newline()
+ generator_flags, OpenOutput)
+
+ # Write python executables to the master ninja.
+ # Let 'python' resolve to what environment is active.
+ # Assume this file is executed using python2.
+ master_ninja.variable('python2', sys.executable)
+ master_ninja.newline()
+
+ # Don't write python3 exectuable until we ensure it's in docker containers.
+ #
+ # python3_executable = 'py -3' if is_windows else 'python3'
+ # cmd = ('{} -c "import os; import sys; '
+ # 'print(os.path.dirname(sys.executable))"').format(python3_executable)
+ # python3_location = subprocess.check_output(cmd, shell=True).strip()
+ # master_ninja.variable('python3', python3_location)
+ # master_ninja.newline()
all_targets = set()
for build_file in params['build_files']:
@@ -1748,7 +1759,7 @@
for config in configurations:
builddir = os.path.join(options.toplevel_dir, 'out', config)
arguments = ['ninja', '-C', builddir]
- print 'Building [%s]: %s' % (config, arguments)
+ print('Building [%s]: %s' % (config, arguments))
subprocess.check_call(arguments)
@@ -1776,10 +1787,10 @@
pool = multiprocessing.Pool(len(config_names))
arglists = []
for config_name in config_names:
- arglists.append((target_list, target_dicts, data, params,
- config_name))
+ arglists.append(
+ (target_list, target_dicts, data, params, config_name))
pool.map(CallGenerateOutputForConfig, arglists)
- except KeyboardInterrupt, e:
+ except KeyboardInterrupt as e:
pool.terminate()
raise e
else:
diff --git a/src/tools/testing/download_from_gcs/clang-format.sha1 b/src/tools/testing/download_from_gcs/clang-format.sha1
new file mode 100644
index 0000000..e6b99ea
--- /dev/null
+++ b/src/tools/testing/download_from_gcs/clang-format.sha1
@@ -0,0 +1 @@
+5349d1954e17f6ccafb6e6663b0f13cdb2bb33c8
diff --git a/src/tools/testing/download_from_gcs/test_dir/clang-format.exe.sha1 b/src/tools/testing/download_from_gcs/test_dir/clang-format.exe.sha1
new file mode 100644
index 0000000..fbb0ae5
--- /dev/null
+++ b/src/tools/testing/download_from_gcs/test_dir/clang-format.exe.sha1
@@ -0,0 +1 @@
+c8455d43d052eb79f65d046c6b02c169857b963b
diff --git a/src/tools/testing/download_from_gcs/test_dir/clang-format.sha1 b/src/tools/testing/download_from_gcs/test_dir/clang-format.sha1
new file mode 100644
index 0000000..8a00b61
--- /dev/null
+++ b/src/tools/testing/download_from_gcs/test_dir/clang-format.sha1
@@ -0,0 +1 @@
+0679b295e2ce2fce7919d1e8d003e497475f24a3
diff --git a/src/v8/BUILD.gn b/src/v8/BUILD.gn
index 11588e9..f70448f 100644
--- a/src/v8/BUILD.gn
+++ b/src/v8/BUILD.gn
@@ -3501,6 +3501,8 @@
"src/base/platform/semaphore.h",
"src/base/platform/time.cc",
"src/base/platform/time.h",
+ "src/base/platform/wrappers.h",
+ "src/base/platform/wrappers_std.cc",
"src/base/region-allocator.cc",
"src/base/region-allocator.h",
"src/base/ring-buffer.h",
diff --git a/src/v8/gypfiles/standalone.gypi b/src/v8/gypfiles/standalone.gypi
index 8f893ce..a2955f8 100644
--- a/src/v8/gypfiles/standalone.gypi
+++ b/src/v8/gypfiles/standalone.gypi
@@ -944,7 +944,6 @@
],
'msvs_settings': {
'VCCLCompilerTool': {
- 'MinimalRebuild': 'false',
'BufferSecurityCheck': 'true',
'EnableFunctionLevelLinking': 'true',
'RuntimeTypeInfo': 'false',
diff --git a/src/v8/include/v8.h b/src/v8/include/v8.h
index a3cb6dd..ca96c32 100644
--- a/src/v8/include/v8.h
+++ b/src/v8/include/v8.h
@@ -15,11 +15,9 @@
#ifndef INCLUDE_V8_H_
#define INCLUDE_V8_H_
-#if !V8_OS_STARBOARD
#include <stddef.h>
#include <stdint.h>
#include <stdio.h>
-#endif // !V8_OS_STARBOARD
#include <memory>
#include <utility>
#include <vector>
diff --git a/src/v8/src/base/atomicops_internals_portable.h b/src/v8/src/base/atomicops_internals_portable.h
index c2a467c..67c5b51 100644
--- a/src/v8/src/base/atomicops_internals_portable.h
+++ b/src/v8/src/base/atomicops_internals_portable.h
@@ -31,10 +31,6 @@
#include <atomic>
-#if defined(V8_OS_STARBOARD)
-#include "starboard/atomic.h"
-#endif
-
#include "src/base/build_config.h"
#include "src/base/macros.h"
@@ -45,9 +41,6 @@
// atomicops.h.
inline void SeqCst_MemoryFence() {
-#if defined(V8_OS_STARBOARD)
- SbAtomicMemoryBarrier();
-#else
#if defined(__GLIBCXX__)
// Work around libstdc++ bug 51038 where atomic_thread_fence was declared but
// not defined, leading to the linker complaining about undefined references.
@@ -55,7 +48,6 @@
#else
std::atomic_thread_fence(std::memory_order_seq_cst);
#endif // defined(__GLIBCXX__)
-#endif // defined(V8_OS_STARBOARD)
}
inline Atomic16 Relaxed_CompareAndSwap(volatile Atomic16* ptr,
@@ -67,82 +59,50 @@
inline Atomic32 Relaxed_CompareAndSwap(volatile Atomic32* ptr,
Atomic32 old_value, Atomic32 new_value) {
-#if defined(V8_OS_STARBOARD)
- return SbAtomicNoBarrier_CompareAndSwap(ptr, old_value, new_value);
-#else
__atomic_compare_exchange_n(ptr, &old_value, new_value, false,
__ATOMIC_RELAXED, __ATOMIC_RELAXED);
return old_value;
-#endif
}
inline Atomic32 Relaxed_AtomicExchange(volatile Atomic32* ptr,
Atomic32 new_value) {
-#if defined(V8_OS_STARBOARD)
- return SbAtomicNoBarrier_Exchange(ptr, new_value);
-#else
return __atomic_exchange_n(ptr, new_value, __ATOMIC_RELAXED);
-#endif
}
inline Atomic32 Relaxed_AtomicIncrement(volatile Atomic32* ptr,
Atomic32 increment) {
-#if defined(V8_OS_STARBOARD)
- return SbAtomicNoBarrier_Increment(ptr, increment);
-#else
return increment + __atomic_fetch_add(ptr, increment, __ATOMIC_RELAXED);
-#endif
}
inline Atomic32 Barrier_AtomicIncrement(volatile Atomic32* ptr,
Atomic32 increment) {
-#if defined(V8_OS_STARBOARD)
- return SbAtomicBarrier_Increment(ptr, increment);
-#else
return increment + __atomic_fetch_add(ptr, increment, __ATOMIC_SEQ_CST);
-#endif
}
inline Atomic32 Acquire_CompareAndSwap(volatile Atomic32* ptr,
Atomic32 old_value, Atomic32 new_value) {
-#if defined(V8_OS_STARBOARD)
- return SbAtomicAcquire_CompareAndSwap(ptr, old_value, new_value);
-#else
__atomic_compare_exchange_n(ptr, &old_value, new_value, false,
__ATOMIC_ACQUIRE, __ATOMIC_ACQUIRE);
return old_value;
-#endif
}
inline Atomic8 Release_CompareAndSwap(volatile Atomic8* ptr, Atomic8 old_value,
Atomic8 new_value) {
-#if defined(V8_OS_STARBOARD)
- return SbAtomicRelease_CompareAndSwap8(ptr, old_value, new_value);
-#else
bool result = __atomic_compare_exchange_n(ptr, &old_value, new_value, false,
__ATOMIC_RELEASE, __ATOMIC_RELAXED);
USE(result); // Make gcc compiler happy.
return old_value;
-#endif
}
inline Atomic32 Release_CompareAndSwap(volatile Atomic32* ptr,
Atomic32 old_value, Atomic32 new_value) {
-#if defined(V8_OS_STARBOARD)
- return SbAtomicRelease_CompareAndSwap(ptr, old_value, new_value);
-#else
__atomic_compare_exchange_n(ptr, &old_value, new_value, false,
__ATOMIC_RELEASE, __ATOMIC_RELAXED);
return old_value;
-#endif
}
inline void Relaxed_Store(volatile Atomic8* ptr, Atomic8 value) {
-#if defined(V8_OS_STARBOARD)
- SbAtomicNoBarrier_Store8(ptr, value);
-#else
__atomic_store_n(ptr, value, __ATOMIC_RELAXED);
-#endif
}
inline void Relaxed_Store(volatile Atomic16* ptr, Atomic16 value) {
@@ -150,27 +110,15 @@
}
inline void Relaxed_Store(volatile Atomic32* ptr, Atomic32 value) {
-#if defined(V8_OS_STARBOARD)
- SbAtomicNoBarrier_Store(ptr, value);
-#else
__atomic_store_n(ptr, value, __ATOMIC_RELAXED);
-#endif
}
inline void Release_Store(volatile Atomic32* ptr, Atomic32 value) {
-#if defined(V8_OS_STARBOARD)
- SbAtomicRelease_Store(ptr, value);
-#else
__atomic_store_n(ptr, value, __ATOMIC_RELEASE);
-#endif
}
inline Atomic8 Relaxed_Load(volatile const Atomic8* ptr) {
-#if defined(V8_OS_STARBOARD)
- return SbAtomicNoBarrier_Load8(ptr);
-#else
return __atomic_load_n(ptr, __ATOMIC_RELAXED);
-#endif
}
inline Atomic16 Relaxed_Load(volatile const Atomic16* ptr) {
@@ -178,113 +126,65 @@
}
inline Atomic32 Relaxed_Load(volatile const Atomic32* ptr) {
-#if defined(V8_OS_STARBOARD)
- return SbAtomicNoBarrier_Load(ptr);
-#else
return __atomic_load_n(ptr, __ATOMIC_RELAXED);
-#endif
}
inline Atomic32 Acquire_Load(volatile const Atomic32* ptr) {
-#if defined(V8_OS_STARBOARD)
- return SbAtomicAcquire_Load(ptr);
-#else
return __atomic_load_n(ptr, __ATOMIC_ACQUIRE);
-#endif
}
#if defined(V8_HOST_ARCH_64_BIT)
inline Atomic64 Relaxed_CompareAndSwap(volatile Atomic64* ptr,
Atomic64 old_value, Atomic64 new_value) {
-#if defined(V8_OS_STARBOARD)
- return SbAtomicNoBarrier_CompareAndSwap64(ptr, old_value, new_value);
-#else
__atomic_compare_exchange_n(ptr, &old_value, new_value, false,
__ATOMIC_RELAXED, __ATOMIC_RELAXED);
return old_value;
-#endif
}
inline Atomic64 Relaxed_AtomicExchange(volatile Atomic64* ptr,
Atomic64 new_value) {
-#if defined(V8_OS_STARBOARD)
- return SbAtomicNoBarrier_Exchange64(ptr, new_value);
-#else
return __atomic_exchange_n(ptr, new_value, __ATOMIC_RELAXED);
-#endif
}
inline Atomic64 Relaxed_AtomicIncrement(volatile Atomic64* ptr,
Atomic64 increment) {
-#if defined(V8_OS_STARBOARD)
- return SbAtomicNoBarrier_Increment64(ptr, increment);
-#else
return increment + __atomic_fetch_add(ptr, increment, __ATOMIC_RELAXED);
-#endif
}
inline Atomic64 Barrier_AtomicIncrement(volatile Atomic64* ptr,
Atomic64 increment) {
-#if defined(V8_OS_STARBOARD)
- return SbAtomicBarrier_Increment64(ptr, increment);
-#else
return increment + __atomic_fetch_add(ptr, increment, __ATOMIC_SEQ_CST);
-#endif
}
inline Atomic64 Acquire_CompareAndSwap(volatile Atomic64* ptr,
Atomic64 old_value, Atomic64 new_value) {
-#if defined(V8_OS_STARBOARD)
- return SbAtomicAcquire_CompareAndSwap64(ptr, old_value, new_value);
-#else
__atomic_compare_exchange_n(ptr, &old_value, new_value, false,
__ATOMIC_ACQUIRE, __ATOMIC_ACQUIRE);
return old_value;
-#endif
}
inline Atomic64 Release_CompareAndSwap(volatile Atomic64* ptr,
Atomic64 old_value, Atomic64 new_value) {
-#if defined(V8_OS_STARBOARD)
- return SbAtomicRelease_CompareAndSwap64(ptr, old_value, new_value);
-#else
__atomic_compare_exchange_n(ptr, &old_value, new_value, false,
__ATOMIC_RELEASE, __ATOMIC_RELAXED);
return old_value;
-#endif
}
inline void Relaxed_Store(volatile Atomic64* ptr, Atomic64 value) {
-#if defined(V8_OS_STARBOARD)
- SbAtomicNoBarrier_Store64(ptr, value);
-#else
__atomic_store_n(ptr, value, __ATOMIC_RELAXED);
-#endif
}
inline void Release_Store(volatile Atomic64* ptr, Atomic64 value) {
-#if defined(V8_OS_STARBOARD)
- SbAtomicRelease_Store64(ptr, value);
-#else
__atomic_store_n(ptr, value, __ATOMIC_RELEASE);
-#endif
}
inline Atomic64 Relaxed_Load(volatile const Atomic64* ptr) {
-#if defined(V8_OS_STARBOARD)
- return SbAtomicNoBarrier_Load64(ptr);
-#else
return __atomic_load_n(ptr, __ATOMIC_RELAXED);
-#endif
}
inline Atomic64 Acquire_Load(volatile const Atomic64* ptr) {
-#if defined(V8_OS_STARBOARD)
- return SbAtomicAcquire_Load64(ptr);
-#else
return __atomic_load_n(ptr, __ATOMIC_ACQUIRE);
-#endif
}
#endif // defined(V8_HOST_ARCH_64_BIT)
diff --git a/src/v8/src/base/hashmap.h b/src/v8/src/base/hashmap.h
index ae0cdd4..ab2811f 100644
--- a/src/v8/src/base/hashmap.h
+++ b/src/v8/src/base/hashmap.h
@@ -15,27 +15,22 @@
#include "src/base/hashmap-entry.h"
#include "src/base/logging.h"
-#if V8_OS_STARBOARD
-
-#include "starboard/common/string.h"
+#if defined(V8_OS_STARBOARD)
#include "starboard/memory.h"
-
-#define malloc(x) SbMemoryAllocate(x)
-#define realloc(x, y) SbMemoryReallocate(x, y)
-#define free(x) SbMemoryDeallocate(x)
-#define memcpy(x, y, z) SbMemoryCopy(x, y, z)
-#define calloc(x, y) SbMemoryCalloc(x, y)
-#define strdup(s) SbStringDuplicate(s)
-
-#endif // V8_OS_STARBOARD
+#endif
namespace v8 {
namespace base {
class DefaultAllocationPolicy {
public:
+#if defined(V8_OS_STARBOARD)
+ V8_INLINE void* New(size_t size) { return SbMemoryAllocate(size); }
+ V8_INLINE static void Delete(void* p) { SbMemoryDeallocate(p); }
+#else
V8_INLINE void* New(size_t size) { return malloc(size); }
V8_INLINE static void Delete(void* p) { free(p); }
+#endif
};
template <typename Key, typename Value, class MatchFun, class AllocationPolicy>
@@ -510,13 +505,4 @@
} // namespace base
} // namespace v8
-#if V8_OS_STARBOARD
-#undef malloc
-#undef realloc
-#undef free
-#undef memcpy
-#undef calloc
-#undef strdup
-#endif
-
#endif // V8_BASE_HASHMAP_H_
diff --git a/src/v8/src/base/logging.cc b/src/v8/src/base/logging.cc
index 1f8035b..c7ffdaa 100644
--- a/src/v8/src/base/logging.cc
+++ b/src/v8/src/base/logging.cc
@@ -5,15 +5,17 @@
#include "src/base/logging.h"
#include <cctype>
-#if !V8_OS_STARBOARD
#include <cstdarg>
#include <cstdio>
#include <cstdlib>
-#endif
#include "src/base/debug/stack_trace.h"
#include "src/base/platform/platform.h"
+#if defined(V8_OS_STARBOARD)
+#include "src/poems.h"
+#endif
+
namespace v8 {
namespace base {
@@ -165,10 +167,8 @@
FailureMessage message(format, arguments);
va_end(arguments);
-#if !V8_OS_STARBOARD
fflush(stdout);
fflush(stderr);
-#endif
// Print the formatted message to stdout without cropping the output.
v8::base::OS::PrintError("\n\n#\n# Fatal error in %s, line %d\n# ", file,
line);
@@ -182,9 +182,7 @@
if (v8::base::g_print_stack_trace) v8::base::g_print_stack_trace();
-#if !V8_OS_STARBOARD
fflush(stderr);
-#endif
v8::base::OS::Abort();
}
diff --git a/src/v8/src/base/platform/platform-starboard.cc b/src/v8/src/base/platform/platform-starboard.cc
index 0caa0d2..711fca5 100644
--- a/src/v8/src/base/platform/platform-starboard.cc
+++ b/src/v8/src/base/platform/platform-starboard.cc
@@ -12,6 +12,7 @@
#include "src/base/platform/time.h"
#include "src/base/timezone-cache.h"
#include "src/base/utils/random-number-generator.h"
+#include "starboard/client_porting/eztime/eztime.h"
#include "starboard/common/condition_variable.h"
#include "starboard/common/log.h"
#include "starboard/common/string.h"
@@ -149,37 +150,6 @@
return result;
}
-// The following code was taken from old v8 to deal with rounding up pointers.
-namespace {
-// Compute the 0-relative offset of some absolute value x of type T.
-// This allows conversion of Addresses and integral types into
-// 0-relative int offsets.
-template <typename T>
-constexpr inline intptr_t OffsetFrom(T x) {
- return x - static_cast<T>(0);
-}
-
-// Compute the absolute value of type T for some 0-relative offset x.
-// This allows conversion of 0-relative int offsets into Addresses and
-// integral types.
-template <typename T>
-constexpr inline T AddressFrom(intptr_t x) {
- return static_cast<T>(static_cast<T>(0) + x);
-}
-
-template <typename T>
-inline T RoundDown(T x, intptr_t m) {
- // m must be a power of two.
- DCHECK(m != 0 && ((m & (m - 1)) == 0));
- return AddressFrom<T>(OffsetFrom(x) & -m);
-}
-
-template <typename T>
-inline T RoundUpOld(T x, intptr_t m) {
- return RoundDown<T>(static_cast<T>(x + m - 1), m);
-}
-} // namespace
-
// static
void* OS::Allocate(void* address, size_t size, size_t alignment,
MemoryPermission access) {
@@ -195,7 +165,8 @@
// Unmap memory allocated before the aligned base address.
uint8_t* base = static_cast<uint8_t*>(result);
- uint8_t* aligned_base = RoundUpOld(base, alignment);
+ uint8_t* aligned_base = reinterpret_cast<uint8_t*>(
+ RoundUp(reinterpret_cast<uintptr_t>(base), alignment));
if (aligned_base != base) {
DCHECK_LT(base, aligned_base);
size_t prefix_size = static_cast<size_t>(aligned_base - base);
@@ -457,7 +428,6 @@
class StarboardTimezoneCache : public TimezoneCache {
public:
- double DaylightSavingsOffset(double time_ms) override { return 0.0; }
void Clear(TimeZoneDetection time_zone_detection) override {}
~StarboardTimezoneCache() override {}
@@ -471,7 +441,18 @@
return SbTimeZoneGetName();
}
double LocalTimeOffset(double time_ms, bool is_utc) override {
- return SbTimeZoneGetCurrent() * 60000.0;
+ // SbTimeZOneGetCurrent returns an offset west of Greenwich, which has the
+ // opposite sign V8 expects.
+ // The starboard function returns offset in minutes. We convert to return
+ // value in milliseconds.
+ return SbTimeZoneGetCurrent() * 60.0 * msPerSecond * (-1);
+ }
+ double DaylightSavingsOffset(double time_ms) override {
+ EzTimeValue value = EzTimeValueFromSbTime(SbTimeGetNow());
+ EzTimeExploded ez_exploded;
+ bool result = EzTimeValueExplode(&value, kEzTimeZoneLocal, &ez_exploded,
+ NULL);
+ return ez_exploded.tm_isdst > 0 ? 3600 * msPerSecond : 0;
}
~StarboardDefaultTimezoneCache() override {}
diff --git a/src/v8/src/base/platform/wrappers.h b/src/v8/src/base/platform/wrappers.h
new file mode 100644
index 0000000..521b06e
--- /dev/null
+++ b/src/v8/src/base/platform/wrappers.h
@@ -0,0 +1,31 @@
+// Copyright 2020 the V8 project 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 V8_BASE_PLATFORM_WRAPPERS_H_
+#define V8_BASE_PLATFORM_WRAPPERS_H_
+
+#include <stddef.h>
+#include <stdio.h>
+
+namespace v8 {
+namespace base {
+
+void* Malloc(size_t size);
+
+void* Realloc(void* memory, size_t size);
+
+void Free(void* memory);
+
+void* Calloc(size_t count, size_t size);
+
+void* Memcpy(void* dest, const void* source, size_t count);
+
+FILE* Fopen(const char* filename, const char* mode);
+
+int Fclose(FILE* stream);
+
+} // namespace base
+} // namespace v8
+
+#endif // V8_BASE_PLATFORM_WRAPPERS_H_
diff --git a/src/v8/src/base/platform/wrappers_starboard.cc b/src/v8/src/base/platform/wrappers_starboard.cc
new file mode 100644
index 0000000..199e753
--- /dev/null
+++ b/src/v8/src/base/platform/wrappers_starboard.cc
@@ -0,0 +1,31 @@
+// Copyright 2020 the V8 project 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 "starboard/memory.h"
+
+#include "src/base/platform/wrappers.h"
+
+namespace v8 {
+namespace base {
+
+void* Malloc(size_t size) { return SbMemoryAlloc(size); }
+
+void* Realloc(void* memory, size_t size) {
+ return SbMemoryReallocate(memory, size);
+}
+
+void Free(void* memory) { return SbMemoryDeallocate(memory); }
+
+void* Calloc(size_t count, size_t size) { return SbMemoryCalloc(count, size); }
+
+void* Memcpy(void* dest, const void* source, size_t count) {
+ return SbMemoryCopy(dest, source, count);
+}
+
+FILE* Fopen(const char* filename, const char* mode) { return NULL; }
+
+int Fclose(FILE* stream) { return -1; }
+
+} // namespace base
+} // namespace v8
diff --git a/src/v8/src/base/platform/wrappers_std.cc b/src/v8/src/base/platform/wrappers_std.cc
new file mode 100644
index 0000000..27ddbd6
--- /dev/null
+++ b/src/v8/src/base/platform/wrappers_std.cc
@@ -0,0 +1,33 @@
+// Copyright 2020 the V8 project 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>
+#include <stdlib.h>
+#include <string.h>
+
+#include "src/base/platform/wrappers.h"
+
+namespace v8 {
+namespace base {
+
+void* Malloc(size_t size) { return malloc(size); }
+
+void* Realloc(void* memory, size_t size) { return realloc(memory, size); }
+
+void Free(void* memory) { return free(memory); }
+
+void* Calloc(size_t count, size_t size) { return calloc(count, size); }
+
+void* Memcpy(void* dest, const void* source, size_t count) {
+ return memcpy(dest, source, count);
+}
+
+FILE* Fopen(const char* filename, const char* mode) {
+ return fopen(filename, mode);
+}
+
+int Fclose(FILE* stream) { return fclose(stream); }
+
+} // namespace base
+} // namespace v8
diff --git a/src/v8/src/base/small-vector.h b/src/v8/src/base/small-vector.h
index 8542808..0350ade 100644
--- a/src/v8/src/base/small-vector.h
+++ b/src/v8/src/base/small-vector.h
@@ -12,18 +12,19 @@
#include "src/base/bits.h"
#include "src/base/macros.h"
-#if defined(STARBOARD)
-// These common Starboard API replacements are not needed for evergreen but
-// some builds can not find definitions for free/malloc above Starboard.
+#if defined(V8_OS_STARBOARD)
#include "starboard/memory.h"
-#include "starboard/string.h"
-#define malloc(x) SbMemoryAllocate(x)
-#define realloc(x, y) SbMemoryReallocate(x, y)
-#define free(x) SbMemoryDeallocate(x)
-#define memcpy(x, y, z) SbMemoryCopy(x, y, z)
-#define calloc(x, y) SbMemoryCalloc(x, y)
-#endif
+struct AllocationPolicy {
+ V8_INLINE static void* Malloc(size_t size) { return SbMemoryAllocate(size); }
+ V8_INLINE static void Free(void* p) { SbMemoryDeallocate(p); }
+};
+#else
+struct AllocationPolicy {
+ V8_INLINE static void* Malloc(size_t size) { return malloc(size); }
+ V8_INLINE static void Free(void* p) { return free(p); }
+};
+#endif // V8_OS_STARBOARD
namespace v8 {
namespace base {
@@ -50,7 +51,7 @@
}
~SmallVector() {
- if (is_big()) free(begin_);
+ if (is_big()) AllocationPolicy::Free(begin_);
}
SmallVector& operator=(const SmallVector& other) V8_NOEXCEPT {
@@ -58,8 +59,8 @@
size_t other_size = other.size();
if (capacity() < other_size) {
// Create large-enough heap-allocated storage.
- if (is_big()) free(begin_);
- begin_ = reinterpret_cast<T*>(malloc(sizeof(T) * other_size));
+ if (is_big()) AllocationPolicy::Free(begin_);
+ begin_ = reinterpret_cast<T*>((sizeof(T) * other_size));
end_of_storage_ = begin_ + other_size;
}
memcpy(begin_, other.begin_, sizeof(T) * other_size);
@@ -70,7 +71,7 @@
SmallVector& operator=(SmallVector&& other) V8_NOEXCEPT {
if (this == &other) return *this;
if (other.is_big()) {
- if (is_big()) free(begin_);
+ if (is_big()) AllocationPolicy::Free(begin_);
begin_ = other.begin_;
end_ = other.end_;
end_of_storage_ = other.end_of_storage_;
@@ -164,9 +165,9 @@
size_t in_use = end_ - begin_;
size_t new_capacity =
base::bits::RoundUpToPowerOfTwo(std::max(min_capacity, 2 * capacity()));
- T* new_storage = reinterpret_cast<T*>(malloc(sizeof(T) * new_capacity));
+ T* new_storage = reinterpret_cast<T*>(AllocationPolicy::Malloc(sizeof(T) * new_capacity));
memcpy(new_storage, begin_, sizeof(T) * in_use);
- if (is_big()) free(begin_);
+ if (is_big()) AllocationPolicy::Free(begin_);
begin_ = new_storage;
end_ = new_storage + in_use;
end_of_storage_ = new_storage + new_capacity;
@@ -184,12 +185,4 @@
} // namespace base
} // namespace v8
-#if defined(STARBOARD)
-#undef malloc
-#undef realloc
-#undef free
-#undef memcpy
-#undef calloc
-#endif
-
#endif // V8_BASE_SMALL_VECTOR_H_
diff --git a/src/v8/src/builtins/builtins.cc b/src/v8/src/builtins/builtins.cc
index 3eb939f..c222ca2 100644
--- a/src/v8/src/builtins/builtins.cc
+++ b/src/v8/src/builtins/builtins.cc
@@ -20,6 +20,10 @@
#include "src/snapshot/embedded/embedded-data.h"
#include "src/utils/ostreams.h"
+#if defined(V8_OS_STARBOARD)
+#include "src/poems.h"
+#endif
+
namespace v8 {
namespace internal {
@@ -213,13 +217,8 @@
const char* builtin_name = name(i);
const char* kind = KindNameOf(i);
Code code = builtin(i);
-#if defined(V8_OS_STARBOARD)
- PrintF((FILE*)nullptr, "%s Builtin, %s, %d\n", kind, builtin_name,
- code.InstructionSize());
-#else
PrintF(stdout, "%s Builtin, %s, %d\n", kind, builtin_name,
code.InstructionSize());
-#endif
}
}
diff --git a/src/v8/src/compiler/graph-reducer.cc b/src/v8/src/compiler/graph-reducer.cc
index 780c04c..9a0dea6 100644
--- a/src/v8/src/compiler/graph-reducer.cc
+++ b/src/v8/src/compiler/graph-reducer.cc
@@ -93,24 +93,20 @@
// {replacement} == {node} represents an in-place reduction. Rerun
// all the other reducers for this node, as now there may be more
// opportunities for reduction.
-#ifndef V8_OS_STARBOARD
if (FLAG_trace_turbo_reduction) {
StdoutStream{} << "- In-place update of " << *node << " by reducer "
<< (*i)->reducer_name() << std::endl;
}
-#endif
skip = i;
i = reducers_.begin();
continue;
} else {
// {node} was replaced by another node.
-#ifndef V8_OS_STARBOARD
if (FLAG_trace_turbo_reduction) {
StdoutStream{} << "- Replacement of " << *node << " with "
<< *(reduction.replacement()) << " by reducer "
<< (*i)->reducer_name() << std::endl;
}
-#endif
return reduction;
}
}
diff --git a/src/v8/src/compiler/node.cc b/src/v8/src/compiler/node.cc
index e447b9c..bc8d77c 100644
--- a/src/v8/src/compiler/node.cc
+++ b/src/v8/src/compiler/node.cc
@@ -4,6 +4,10 @@
#include "src/compiler/node.h"
+#if defined(V8_OS_STARBOARD)
+#include "src/poems.h"
+#endif
+
namespace v8 {
namespace internal {
namespace compiler {
@@ -370,9 +374,7 @@
#if DEBUG
void Node::Verify() {
// Check basic sanity of input data structures.
-#ifndef V8_OS_STARBOARD
fflush(stdout);
-#endif
int count = this->InputCount();
// Avoid quadratic explosion for mega nodes; only verify if the input
// count is less than 200 or is a round number of 100s.
diff --git a/src/v8/src/diagnostics/objects-printer.cc b/src/v8/src/diagnostics/objects-printer.cc
index 57db1af..3e60c65 100644
--- a/src/v8/src/diagnostics/objects-printer.cc
+++ b/src/v8/src/diagnostics/objects-printer.cc
@@ -71,7 +71,7 @@
#if defined(STARBOARD)
#include "starboard/common/log.h"
-#define printf(format) SbLogRaw(format)
+#include "src/poems.h"
#endif
namespace v8 {
diff --git a/src/v8/src/execution/isolate.cc b/src/v8/src/execution/isolate.cc
index 409c89c..58cc241 100644
--- a/src/v8/src/execution/isolate.cc
+++ b/src/v8/src/execution/isolate.cc
@@ -4,14 +4,10 @@
#include "src/execution/isolate.h"
-#if !V8_OS_STARBOARD
#include <stdlib.h>
-#endif // V8_OS_STARBOARD
#include <atomic>
-#if !defined(V8_OS_STARBOARD)
#include <fstream> // NOLINT(readability/streams)
-#endif
#include <memory>
#include <sstream>
#include <unordered_map>
diff --git a/src/v8/src/flags/flags.h b/src/v8/src/flags/flags.h
index 3fe8b1b..5f0a6d0 100644
--- a/src/v8/src/flags/flags.h
+++ b/src/v8/src/flags/flags.h
@@ -8,9 +8,7 @@
#include <vector>
#include "src/common/globals.h"
-#if !defined(DISABLE_WASM_STARBOARD)
#include "src/wasm/wasm-limits.h"
-#endif
namespace v8 {
namespace internal {
diff --git a/src/v8/src/heap/heap.cc b/src/v8/src/heap/heap.cc
index 04c4113..99539a9 100644
--- a/src/v8/src/heap/heap.cc
+++ b/src/v8/src/heap/heap.cc
@@ -79,6 +79,10 @@
// Has to be the last include (doesn't have include guards):
#include "src/objects/object-macros.h"
+#if defined(V8_OS_STARBOARD)
+#include "src/poems.h"
+#endif
+
namespace v8 {
namespace internal {
@@ -3777,9 +3781,7 @@
void Heap::Print() {
if (!HasBeenSetUp()) return;
-#ifndef V8_OS_STARBOARD
isolate()->PrintStack(stdout);
-#endif
for (SpaceIterator it(this); it.HasNext();) {
it.Next()->Print();
diff --git a/src/v8/src/heap/heap.h b/src/v8/src/heap/heap.h
index 898bc07..81f2b0d 100644
--- a/src/v8/src/heap/heap.h
+++ b/src/v8/src/heap/heap.h
@@ -29,9 +29,7 @@
#include "src/objects/visitors.h"
#include "src/roots/roots.h"
#include "src/utils/allocation.h"
-#if !defined(STARBOARD)
#include "testing/gtest/include/gtest/gtest_prod.h"
-#endif
namespace v8 {
diff --git a/src/v8/src/init/v8.cc b/src/v8/src/init/v8.cc
index 9175e2d..8edd816 100644
--- a/src/v8/src/init/v8.cc
+++ b/src/v8/src/init/v8.cc
@@ -6,10 +6,6 @@
#include <fstream>
-#if V8_OS_STARBOARD
-#include "src/poems.h"
-#endif
-
#include "src/api/api.h"
#include "src/base/atomicops.h"
#include "src/base/once.h"
@@ -32,6 +28,10 @@
#include "src/tracing/tracing-category-observer.h"
#include "src/wasm/wasm-engine.h"
+#if V8_OS_STARBOARD
+#include "src/poems.h"
+#endif
+
namespace v8 {
namespace internal {
@@ -74,7 +74,7 @@
FLAG_max_semi_space_size = 1;
}
-#if !defined(DISABLE_GRAPHS_STARBOARD)
+#if !defined(V8_OS_STARBOARD)
if (FLAG_trace_turbo) {
// Create an empty file shared by the process (e.g. the wasm engine).
std::ofstream(Isolate::GetTurboCfgFileName(nullptr).c_str(),
diff --git a/src/v8/src/logging/log-utils.cc b/src/v8/src/logging/log-utils.cc
index 934afdd..8047329 100644
--- a/src/v8/src/logging/log-utils.cc
+++ b/src/v8/src/logging/log-utils.cc
@@ -4,10 +4,6 @@
#include "src/logging/log-utils.h"
-#if V8_OS_STARBOARD
-#include "starboard/common/log.h"
-#endif
-
#include "src/base/platform/platform.h"
#include "src/common/assert-scope.h"
#include "src/objects/objects-inl.h"
@@ -16,6 +12,10 @@
#include "src/utils/vector.h"
#include "src/utils/version.h"
+#if V8_OS_STARBOARD
+#include "src/poems.h"
+#endif
+
namespace v8 {
namespace internal {
@@ -27,10 +27,8 @@
// If we're logging anything, we need to open the log file.
if (!Log::InitLogAtStart()) {
return nullptr;
-#ifndef V8_OS_STARBOARD
} else if (strcmp(file_name, kLogToConsole) == 0) {
return stdout;
-#endif
} else if (strcmp(file_name, kLogToTemporaryFile) == 0) {
return base::OS::OpenTemporaryFile();
} else {
@@ -41,11 +39,7 @@
Log::Log(Logger* logger, const char* file_name)
: is_stopped_(false),
output_handle_(Log::CreateOutputHandle(file_name)),
-#if defined(V8_OS_STARBOARD)
- os_(output_handle_),
-#else
os_(output_handle_ == nullptr ? stdout : output_handle_),
-#endif
format_buffer_(NewArray<char>(kMessageBufferSize)),
logger_(logger) {
// --log-all enables all the log flags.
diff --git a/src/v8/src/logging/log-utils.h b/src/v8/src/logging/log-utils.h
index e6c34a8..bc5b09d 100644
--- a/src/v8/src/logging/log-utils.h
+++ b/src/v8/src/logging/log-utils.h
@@ -5,9 +5,7 @@
#ifndef V8_LOGGING_LOG_UTILS_H_
#define V8_LOGGING_LOG_UTILS_H_
-#if !V8_OS_STARBOARD
#include <stdio.h>
-#endif
#include <cstdarg>
diff --git a/src/v8/src/poems.h b/src/v8/src/poems.h
index fec8c0a..4ac3cae 100644
--- a/src/v8/src/poems.h
+++ b/src/v8/src/poems.h
@@ -12,67 +12,28 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-// Specialized poems for porting V8 on top of Starboard. It would have been
+// Specialized defines for porting V8 on top of Starboard. It would have been
// nice to have been able to use the shared poems, however they are too
// aggressive for V8 (such as grabbing identifiers that will come after std::).
#ifndef V8_SRC_POEMS_H_
#define V8_SRC_POEMS_H_
-#if !defined(STARBOARD)
-#error "Including V8 poems without STARBOARD defined."
-#endif
-
#if !defined(V8_OS_STARBOARD)
#error "Including V8 poems without V8_OS_STARBOARD defined."
#endif
#include "starboard/memory.h"
#include "starboard/string.h"
-
-#ifdef __cplusplus
-
-// Declaring the following functions static inline is not necessary in C++. See:
-// http://stackoverflow.com/questions/10847176/should-i-define-static-inline-methods-in-header-file
-
-// Finds the first occurrence of |character| in |str|, returning a pointer to
-// the found character in the given string, or NULL if not found.
-// Meant to be a drop-in replacement for strchr
-inline char* PoemFindCharacterInString(char* str, int character) {
- const char* const_str = static_cast<const char*>(str);
- const char c = static_cast<char>(character);
- return const_cast<char*>(SbStringFindCharacter(const_str, c));
-}
-
-// Finds the first occurrence of |character| in |str|, returning a pointer to
-// the found character in the given string, or NULL if not found.
-// Meant to be a drop-in replacement for strchr
-inline const char* PoemFindCharacterInString(const char* str, int character) {
- const char c = static_cast<char>(character);
- return SbStringFindCharacter(str, c);
-}
-
-#else
-
-// Finds the first occurrence of |character| in |str|, returning a pointer to
-// the found character in the given string, or NULL if not found.
-// Meant to be a drop-in replacement for strchr
-static SB_C_INLINE char* PoemFindCharacterInString(const char* str,
- int character) {
- // C-style cast used for C code
- return (char*)(SbStringFindCharacter(str, character));
-}
-#endif
+#include "starboard/common/log.h"
#define malloc(x) SbMemoryAllocate(x)
#define realloc(x, y) SbMemoryReallocate(x, y)
#define free(x) SbMemoryDeallocate(x)
-#define memcpy(x, y, z) SbMemoryCopy(x, y, z)
#define calloc(x, y) SbMemoryCalloc(x, y)
#define strdup(s) SbStringDuplicate(s)
-#define snprintf(a, b, c, ...) SbStringFormatF(a, b, c, __VA_ARGS__)
-#define strchr(s, c) PoemFindCharacterInString(s, c)
-#define memchr(s, c, n) SbMemoryFindByte(s, c, n)
+#define printf(x) SbLogRaw(x)
+#define __builtin_abort SbSystemBreakIntoDebugger
// No-ops for now
#define fopen(x)
@@ -85,6 +46,13 @@
#define ftell(x) -1L
#define puts(x)
#define fputs(x)
+#define fprintf(x, y, z)
+static FILE* null_file_ptr = nullptr;
+#undef stderr
+#define stderr null_file_ptr
+#undef stdout
+#define stdout null_file_ptr
+#define fflush(x)
#endif // V8_SRC_POEMS_H_
diff --git a/src/v8/src/runtime/runtime-atomics.cc b/src/v8/src/runtime/runtime-atomics.cc
index 3898a26..a3a75fa 100644
--- a/src/v8/src/runtime/runtime-atomics.cc
+++ b/src/v8/src/runtime/runtime-atomics.cc
@@ -11,10 +11,6 @@
#include "src/objects/js-array-buffer-inl.h"
#include "src/runtime/runtime-utils.h"
-#if defined(V8_OS_STARBOARD)
-#include "starboard/common/log.h"
-#endif // V8_OS_STARBOARD
-
// Implement Atomic accesses to SharedArrayBuffers as defined in the
// SharedArrayBuffer draft spec, found here
// https://github.com/tc39/ecmascript_sharedmem
@@ -32,43 +28,43 @@
template <typename T>
inline T ExchangeSeqCst(T* p, T value) {
- SB_NOTREACHED();
+ CHECK(false);
return 0;
}
template <typename T>
inline T CompareExchangeSeqCst(T* p, T oldval, T newval) {
- SB_NOTREACHED();
+ CHECK(false);
return 0;
}
template <typename T>
inline T AddSeqCst(T* p, T value) {
- SB_NOTREACHED();
+ CHECK(false);
return 0;
}
template <typename T>
inline T SubSeqCst(T* p, T value) {
- SB_NOTREACHED();
+ CHECK(false);
return 0;
}
template <typename T>
inline T AndSeqCst(T* p, T value) {
- SB_NOTREACHED();
+ CHECK(false);
return 0;
}
template <typename T>
inline T OrSeqCst(T* p, T value) {
- SB_NOTREACHED();
+ CHECK(false);
return 0;
}
template <typename T>
inline T XorSeqCst(T* p, T value) {
- SB_NOTREACHED();
+ CHECK(false);
return 0;
}
diff --git a/src/v8/src/runtime/runtime-test.cc b/src/v8/src/runtime/runtime-test.cc
index f0caaaa..e605c74 100644
--- a/src/v8/src/runtime/runtime-test.cc
+++ b/src/v8/src/runtime/runtime-test.cc
@@ -35,6 +35,10 @@
#include "src/wasm/wasm-objects-inl.h"
#include "src/wasm/wasm-serialization.h"
+#if defined(V8_OS_STARBOARD)
+#include "src/poems.h"
+#endif
+
namespace v8 {
namespace internal {
diff --git a/src/v8/src/snapshot/embedded/embedded-file-writer.h b/src/v8/src/snapshot/embedded/embedded-file-writer.h
index b886e42..c26465a 100644
--- a/src/v8/src/snapshot/embedded/embedded-file-writer.h
+++ b/src/v8/src/snapshot/embedded/embedded-file-writer.h
@@ -6,9 +6,7 @@
#define V8_SNAPSHOT_EMBEDDED_EMBEDDED_FILE_WRITER_H_
#include <cinttypes>
-#if !defined(V8_OS_STARBOARD)
#include <cstdio>
-#endif
#include <cstring>
#include "src/common/globals.h"
diff --git a/src/v8/src/snapshot/embedded/platform-embedded-file-writer-base.h b/src/v8/src/snapshot/embedded/platform-embedded-file-writer-base.h
index f9416c2..b0d1714 100644
--- a/src/v8/src/snapshot/embedded/platform-embedded-file-writer-base.h
+++ b/src/v8/src/snapshot/embedded/platform-embedded-file-writer-base.h
@@ -6,9 +6,7 @@
#define V8_SNAPSHOT_EMBEDDED_PLATFORM_EMBEDDED_FILE_WRITER_BASE_H_
#include <cinttypes>
-#if !defined(V8_OS_STARBOARD)
#include <cstdio> // For FILE.
-#endif
#include <memory>
namespace v8 {
diff --git a/src/v8/src/trap-handler/handler-outside.cc b/src/v8/src/trap-handler/handler-outside.cc
index f87c1ff..55e3c6f 100644
--- a/src/v8/src/trap-handler/handler-outside.cc
+++ b/src/v8/src/trap-handler/handler-outside.cc
@@ -19,11 +19,6 @@
//
// For the code that runs in the trap handler itself, see handler-inside.cc.
-#if defined(V8_OS_STARBOARD)
-#include "starboard/system.h"
-#define __builtin_abort SbSystemBreakIntoDebugger
-#endif
-
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
@@ -39,11 +34,6 @@
#include "src/poems.h"
#endif
-#if defined(V8_OS_STARBOARD)
-#include "starboard/system.h"
-#define abort SbSystemBreakIntoDebugger
-#endif
-
namespace {
size_t gNextCodeObject = 0;
diff --git a/src/v8/src/utils/allocation.cc b/src/v8/src/utils/allocation.cc
index a1e8468..104b176 100644
--- a/src/v8/src/utils/allocation.cc
+++ b/src/v8/src/utils/allocation.cc
@@ -148,6 +148,8 @@
#elif V8_LIBC_BIONIC
// Using free is not correct in general, but for V8_LIBC_BIONIC it is.
free(ptr);
+#elif V8_OS_STARBOARD
+ SbMemoryDeallocateAligned(ptr);
#else
free(ptr);
#endif
diff --git a/src/v8/src/utils/ostreams.h b/src/v8/src/utils/ostreams.h
index 5ad1018..620b51e 100644
--- a/src/v8/src/utils/ostreams.h
+++ b/src/v8/src/utils/ostreams.h
@@ -5,11 +5,9 @@
#ifndef V8_UTILS_OSTREAMS_H_
#define V8_UTILS_OSTREAMS_H_
-#if !defined(V8_OS_STARBOARD)
#include <cstddef>
#include <cstdio>
#include <cstring>
-#endif
#include <ostream> // NOLINT
#include <streambuf>
diff --git a/src/v8/test/unittests/profiler/strings-storage-unittest.cc b/src/v8/test/unittests/profiler/strings-storage-unittest.cc
index 3b561ba..31225f4 100644
--- a/src/v8/test/unittests/profiler/strings-storage-unittest.cc
+++ b/src/v8/test/unittests/profiler/strings-storage-unittest.cc
@@ -4,9 +4,7 @@
#include "src/profiler/strings-storage.h"
-#if !V8_OS_STARBOARD
#include <cstdio>
-#endif
#include "test/unittests/test-utils.h"
#include "testing/gtest/include/gtest/gtest.h"