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"