Import Cobalt 6.16000
diff --git a/src/base/base.gypi b/src/base/base.gypi
index 79b9dd4..c1a5fff 100644
--- a/src/base/base.gypi
+++ b/src/base/base.gypi
@@ -589,11 +589,6 @@
['include', 'sys_string_conversions_linux.cc'],
],
}],
- [ 'OS=="lb_shell" and target_arch!="linux" and target_arch!="android"', {
- 'sources!': [
- 'string16.cc', # wchar_t is 2-bytes wide, string16 == wstring here.
- ],
- }],
[ 'OS=="lb_shell" and target_arch=="android"', {
'sources/' : [
['exclude', 'message_pump_shell.cc'],
@@ -660,14 +655,6 @@
# We use thread_checker_impl_atomic.cc instead.
'threading/thread_checker_impl.cc',
],
- 'conditions': [
- ['target_os!="linux" and target_os!="android"', {
- 'sources!': [
- # Since wchar_t is 2-bytes wide, string16 == wstring here.
- 'string16.cc',
- ],
- }],
- ],
}], # OS == "starboard"
[ 'OS=="lb_shell" or OS=="starboard"', {
'sources!': [
diff --git a/src/base/string16.cc b/src/base/string16.cc
index 930e09f..9c5acb7 100644
--- a/src/base/string16.cc
+++ b/src/base/string16.cc
@@ -4,14 +4,9 @@
#include "base/string16.h"
-#if defined(WCHAR_T_IS_UTF16)
-#error This file should not be used on 2-byte wchar_t systems
-// If this winds up being needed on 2-byte wchar_t systems, either the
-// definitions below can be used, or the host system's wide character
-// functions like wmemcmp can be wrapped.
-
-#elif defined(WCHAR_T_IS_UTF32)
+// See discussion in string16.h: This is only needed on 32-bit wchar_t systems.
+#if defined(WCHAR_T_IS_UTF32)
#include <ostream>
diff --git a/src/cobalt/audio/audio_destination_node.cc b/src/cobalt/audio/audio_destination_node.cc
index 59d80df..e0eda2b 100644
--- a/src/cobalt/audio/audio_destination_node.cc
+++ b/src/cobalt/audio/audio_destination_node.cc
@@ -38,8 +38,6 @@
: AudioNode(context), max_channel_count_(kMaxChannelCount) {
AudioLock::AutoLock lock(audio_lock());
- audio_device_.reset(
- new AudioDevice(static_cast<int>(channel_count(NULL)), this));
AddInput(new AudioNodeInput(this));
}
@@ -54,6 +52,15 @@
RemoveAllInputs();
}
+void AudioDestinationNode::OnInputNodeConnected() {
+ audio_lock()->AssertLocked();
+
+ if (!audio_device_) {
+ audio_device_.reset(
+ new AudioDevice(static_cast<int>(channel_count(NULL)), this));
+ }
+}
+
void AudioDestinationNode::FillAudioBus(ShellAudioBus* audio_bus,
bool* silence) {
// This is called by Audio thread.
diff --git a/src/cobalt/audio/audio_destination_node.h b/src/cobalt/audio/audio_destination_node.h
index 14fab99..50bfe7e 100644
--- a/src/cobalt/audio/audio_destination_node.h
+++ b/src/cobalt/audio/audio_destination_node.h
@@ -48,7 +48,8 @@
uint32 max_channel_count() const { return max_channel_count_; }
// From AudioNode.
- scoped_ptr<ShellAudioBus> PassAudioBusFromSource(int32, /*number_of_frames*/
+ void OnInputNodeConnected() OVERRIDE;
+ scoped_ptr<ShellAudioBus> PassAudioBusFromSource(int32 /*number_of_frames*/,
SampleType) OVERRIDE {
NOTREACHED();
return scoped_ptr<ShellAudioBus>();
diff --git a/src/cobalt/audio/audio_node.h b/src/cobalt/audio/audio_node.h
index 9564898..01a578d 100644
--- a/src/cobalt/audio/audio_node.h
+++ b/src/cobalt/audio/audio_node.h
@@ -111,6 +111,9 @@
// Disconnects an AudioNode's output.
void Disconnect(uint32 output, script::ExceptionState* exception_state);
+ // Called when a new input node has been connected.
+ virtual void OnInputNodeConnected() {}
+
// TODO: Support wrapping ShellAudioBus into another ShellAudioBus.
virtual scoped_ptr<ShellAudioBus> PassAudioBusFromSource(
int32 number_of_frames, SampleType sample_type) = 0;
diff --git a/src/cobalt/audio/audio_node_input.cc b/src/cobalt/audio/audio_node_input.cc
index b0c8597..b7ac086 100644
--- a/src/cobalt/audio/audio_node_input.cc
+++ b/src/cobalt/audio/audio_node_input.cc
@@ -197,6 +197,7 @@
output->AddInput(this);
outputs_.insert(output);
+ owner_node_->OnInputNodeConnected();
}
void AudioNodeInput::Disconnect(AudioNodeOutput* output) {
diff --git a/src/cobalt/bindings/generated/mozjs/testing/MozjsAnonymousIndexedGetterInterface.cc b/src/cobalt/bindings/generated/mozjs/testing/MozjsAnonymousIndexedGetterInterface.cc
index ff82636..9a486e9 100644
--- a/src/cobalt/bindings/generated/mozjs/testing/MozjsAnonymousIndexedGetterInterface.cc
+++ b/src/cobalt/bindings/generated/mozjs/testing/MozjsAnonymousIndexedGetterInterface.cc
@@ -86,7 +86,6 @@
bool IsSupportedIndexProperty(JSContext* context, JS::HandleObject object,
uint32_t index) {
- TRACE_EVENT0("cobalt::bindings", "IsSupportedIndexProperty");
WrapperPrivate* wrapper_private =
WrapperPrivate::GetFromObject(context, object);
AnonymousIndexedGetterInterface* impl =
@@ -109,7 +108,6 @@
JSBool GetIndexedProperty(
JSContext* context, JS::HandleObject object, JS::HandleId id,
JS::MutableHandleValue vp) {
- TRACE_EVENT0("cobalt::bindings", "GetIndexedProperty");
JS::RootedValue id_value(context);
if (!JS_IdToValue(context, id, id_value.address())) {
NOTREACHED();
diff --git a/src/cobalt/bindings/generated/mozjs/testing/MozjsAnonymousNamedGetterInterface.cc b/src/cobalt/bindings/generated/mozjs/testing/MozjsAnonymousNamedGetterInterface.cc
index a896d35..5431665 100644
--- a/src/cobalt/bindings/generated/mozjs/testing/MozjsAnonymousNamedGetterInterface.cc
+++ b/src/cobalt/bindings/generated/mozjs/testing/MozjsAnonymousNamedGetterInterface.cc
@@ -86,7 +86,6 @@
bool IsSupportedNamedProperty(JSContext* context, JS::HandleObject object,
const std::string& property_name) {
- TRACE_EVENT0("cobalt::bindings", "IsSupportedNamedProperty");
WrapperPrivate* wrapper_private =
WrapperPrivate::GetFromObject(context, object);
AnonymousNamedGetterInterface* impl =
diff --git a/src/cobalt/bindings/generated/mozjs/testing/MozjsAnonymousNamedIndexedGetterInterface.cc b/src/cobalt/bindings/generated/mozjs/testing/MozjsAnonymousNamedIndexedGetterInterface.cc
index 8f883ff..0d132c4 100644
--- a/src/cobalt/bindings/generated/mozjs/testing/MozjsAnonymousNamedIndexedGetterInterface.cc
+++ b/src/cobalt/bindings/generated/mozjs/testing/MozjsAnonymousNamedIndexedGetterInterface.cc
@@ -86,7 +86,6 @@
bool IsSupportedNamedProperty(JSContext* context, JS::HandleObject object,
const std::string& property_name) {
- TRACE_EVENT0("cobalt::bindings", "IsSupportedNamedProperty");
WrapperPrivate* wrapper_private =
WrapperPrivate::GetFromObject(context, object);
AnonymousNamedIndexedGetterInterface* impl =
@@ -178,7 +177,6 @@
bool IsSupportedIndexProperty(JSContext* context, JS::HandleObject object,
uint32_t index) {
- TRACE_EVENT0("cobalt::bindings", "IsSupportedIndexProperty");
WrapperPrivate* wrapper_private =
WrapperPrivate::GetFromObject(context, object);
AnonymousNamedIndexedGetterInterface* impl =
@@ -201,7 +199,6 @@
JSBool GetIndexedProperty(
JSContext* context, JS::HandleObject object, JS::HandleId id,
JS::MutableHandleValue vp) {
- TRACE_EVENT0("cobalt::bindings", "GetIndexedProperty");
JS::RootedValue id_value(context);
if (!JS_IdToValue(context, id, id_value.address())) {
NOTREACHED();
diff --git a/src/cobalt/bindings/generated/mozjs/testing/MozjsDerivedGetterSetterInterface.cc b/src/cobalt/bindings/generated/mozjs/testing/MozjsDerivedGetterSetterInterface.cc
index 1c88411..7c48cfc 100644
--- a/src/cobalt/bindings/generated/mozjs/testing/MozjsDerivedGetterSetterInterface.cc
+++ b/src/cobalt/bindings/generated/mozjs/testing/MozjsDerivedGetterSetterInterface.cc
@@ -86,7 +86,6 @@
bool IsSupportedNamedProperty(JSContext* context, JS::HandleObject object,
const std::string& property_name) {
- TRACE_EVENT0("cobalt::bindings", "IsSupportedNamedProperty");
WrapperPrivate* wrapper_private =
WrapperPrivate::GetFromObject(context, object);
DerivedGetterSetterInterface* impl =
@@ -178,7 +177,6 @@
bool IsSupportedIndexProperty(JSContext* context, JS::HandleObject object,
uint32_t index) {
- TRACE_EVENT0("cobalt::bindings", "IsSupportedIndexProperty");
WrapperPrivate* wrapper_private =
WrapperPrivate::GetFromObject(context, object);
DerivedGetterSetterInterface* impl =
@@ -201,7 +199,6 @@
JSBool GetIndexedProperty(
JSContext* context, JS::HandleObject object, JS::HandleId id,
JS::MutableHandleValue vp) {
- TRACE_EVENT0("cobalt::bindings", "GetIndexedProperty");
JS::RootedValue id_value(context);
if (!JS_IdToValue(context, id, id_value.address())) {
NOTREACHED();
diff --git a/src/cobalt/bindings/generated/mozjs/testing/MozjsIndexedGetterInterface.cc b/src/cobalt/bindings/generated/mozjs/testing/MozjsIndexedGetterInterface.cc
index b362b42..66f6497 100644
--- a/src/cobalt/bindings/generated/mozjs/testing/MozjsIndexedGetterInterface.cc
+++ b/src/cobalt/bindings/generated/mozjs/testing/MozjsIndexedGetterInterface.cc
@@ -86,7 +86,6 @@
bool IsSupportedIndexProperty(JSContext* context, JS::HandleObject object,
uint32_t index) {
- TRACE_EVENT0("cobalt::bindings", "IsSupportedIndexProperty");
WrapperPrivate* wrapper_private =
WrapperPrivate::GetFromObject(context, object);
IndexedGetterInterface* impl =
@@ -109,7 +108,6 @@
JSBool GetIndexedProperty(
JSContext* context, JS::HandleObject object, JS::HandleId id,
JS::MutableHandleValue vp) {
- TRACE_EVENT0("cobalt::bindings", "GetIndexedProperty");
JS::RootedValue id_value(context);
if (!JS_IdToValue(context, id, id_value.address())) {
NOTREACHED();
diff --git a/src/cobalt/bindings/generated/mozjs/testing/MozjsNamedGetterInterface.cc b/src/cobalt/bindings/generated/mozjs/testing/MozjsNamedGetterInterface.cc
index 79fb735..51f1f54 100644
--- a/src/cobalt/bindings/generated/mozjs/testing/MozjsNamedGetterInterface.cc
+++ b/src/cobalt/bindings/generated/mozjs/testing/MozjsNamedGetterInterface.cc
@@ -86,7 +86,6 @@
bool IsSupportedNamedProperty(JSContext* context, JS::HandleObject object,
const std::string& property_name) {
- TRACE_EVENT0("cobalt::bindings", "IsSupportedNamedProperty");
WrapperPrivate* wrapper_private =
WrapperPrivate::GetFromObject(context, object);
NamedGetterInterface* impl =
diff --git a/src/cobalt/bindings/generated/mozjs/testing/MozjsNamedIndexedGetterInterface.cc b/src/cobalt/bindings/generated/mozjs/testing/MozjsNamedIndexedGetterInterface.cc
index e027bc0..2715fd9 100644
--- a/src/cobalt/bindings/generated/mozjs/testing/MozjsNamedIndexedGetterInterface.cc
+++ b/src/cobalt/bindings/generated/mozjs/testing/MozjsNamedIndexedGetterInterface.cc
@@ -86,7 +86,6 @@
bool IsSupportedNamedProperty(JSContext* context, JS::HandleObject object,
const std::string& property_name) {
- TRACE_EVENT0("cobalt::bindings", "IsSupportedNamedProperty");
WrapperPrivate* wrapper_private =
WrapperPrivate::GetFromObject(context, object);
NamedIndexedGetterInterface* impl =
@@ -178,7 +177,6 @@
bool IsSupportedIndexProperty(JSContext* context, JS::HandleObject object,
uint32_t index) {
- TRACE_EVENT0("cobalt::bindings", "IsSupportedIndexProperty");
WrapperPrivate* wrapper_private =
WrapperPrivate::GetFromObject(context, object);
NamedIndexedGetterInterface* impl =
@@ -201,7 +199,6 @@
JSBool GetIndexedProperty(
JSContext* context, JS::HandleObject object, JS::HandleId id,
JS::MutableHandleValue vp) {
- TRACE_EVENT0("cobalt::bindings", "GetIndexedProperty");
JS::RootedValue id_value(context);
if (!JS_IdToValue(context, id, id_value.address())) {
NOTREACHED();
diff --git a/src/cobalt/bindings/generated/mozjs/testing/MozjsSingleOperationInterface.cc b/src/cobalt/bindings/generated/mozjs/testing/MozjsSingleOperationInterface.cc
index 2bd13c6..36e73dd 100644
--- a/src/cobalt/bindings/generated/mozjs/testing/MozjsSingleOperationInterface.cc
+++ b/src/cobalt/bindings/generated/mozjs/testing/MozjsSingleOperationInterface.cc
@@ -27,6 +27,7 @@
#include "cobalt/script/logging_exception_state.h"
#include "cobalt/script/mozjs/conversion_helpers.h"
#include "cobalt/script/mozjs/mozjs_callback_interface.h"
+#include "cobalt/script/mozjs/util/exception_helpers.h"
#include "third_party/mozjs/js/src/jsapi.h"
#include "third_party/mozjs/js/src/jscntxt.h"
@@ -40,6 +41,7 @@
using cobalt::script::mozjs::FromJSValue;
using cobalt::script::mozjs::GetCallableForCallbackInterface;
using cobalt::script::mozjs::ToJSValue;
+using cobalt::script::mozjs::util::GetExceptionString;
} // namespace
namespace cobalt {
@@ -90,7 +92,8 @@
DCHECK(function);
success = JS::Call(context_, this_value, function, kNumArguments, args,
return_value.address());
- DLOG_IF(WARNING, !success) << "Exception in callback.";
+ DLOG_IF(WARNING, !success) << "Exception in callback: "
+ << GetExceptionString(context_);
if (success) {
LoggingExceptionState exception_state;
FromJSValue(context_, return_value, 0, &exception_state,
diff --git a/src/cobalt/bindings/mozjs/templates/callback-interface.cc.template b/src/cobalt/bindings/mozjs/templates/callback-interface.cc.template
index 115f228..895e453 100644
--- a/src/cobalt/bindings/mozjs/templates/callback-interface.cc.template
+++ b/src/cobalt/bindings/mozjs/templates/callback-interface.cc.template
@@ -20,6 +20,7 @@
#include "cobalt/script/logging_exception_state.h"
#include "cobalt/script/mozjs/conversion_helpers.h"
#include "cobalt/script/mozjs/mozjs_callback_interface.h"
+#include "cobalt/script/mozjs/util/exception_helpers.h"
#include "third_party/mozjs/js/src/jsapi.h"
#include "third_party/mozjs/js/src/jscntxt.h"
{% endblock includes %}
@@ -30,6 +31,7 @@
using cobalt::script::mozjs::FromJSValue;
using cobalt::script::mozjs::GetCallableForCallbackInterface;
using cobalt::script::mozjs::ToJSValue;
+using cobalt::script::mozjs::util::GetExceptionString;
{% endblock using_directives %}
{% block implementation %}
@@ -90,7 +92,8 @@
DCHECK(function);
success = JS::Call(context_, this_value, function, kNumArguments, args,
return_value.address());
- DLOG_IF(WARNING, !success) << "Exception in callback.";
+ DLOG_IF(WARNING, !success) << "Exception in callback: "
+ << GetExceptionString(context_);
{% if overload.type != 'void' %}
if (success) {
LoggingExceptionState exception_state;
diff --git a/src/cobalt/bindings/mozjs/templates/interface.cc.template b/src/cobalt/bindings/mozjs/templates/interface.cc.template
index 3307b67..b92a526 100644
--- a/src/cobalt/bindings/mozjs/templates/interface.cc.template
+++ b/src/cobalt/bindings/mozjs/templates/interface.cc.template
@@ -126,7 +126,6 @@
{% if named_property_getter %}
bool IsSupportedNamedProperty(JSContext* context, JS::HandleObject object,
const std::string& property_name) {
- TRACE_EVENT0("cobalt::bindings", "IsSupportedNamedProperty");
{{ get_impl_class_instance(impl_class) }}
return impl->CanQueryNamedProperty(property_name);
}
@@ -215,7 +214,6 @@
{% if indexed_property_getter %}
bool IsSupportedIndexProperty(JSContext* context, JS::HandleObject object,
uint32_t index) {
- TRACE_EVENT0("cobalt::bindings", "IsSupportedIndexProperty");
{{ get_impl_class_instance(impl_class) }}
return index < impl->length();
}
@@ -232,7 +230,6 @@
JSBool GetIndexedProperty(
JSContext* context, JS::HandleObject object, JS::HandleId id,
JS::MutableHandleValue vp) {
- TRACE_EVENT0("cobalt::bindings", "GetIndexedProperty");
JS::RootedValue id_value(context);
if (!JS_IdToValue(context, id, id_value.address())) {
NOTREACHED();
diff --git a/src/cobalt/browser/application.cc b/src/cobalt/browser/application.cc
index ffded5e..470eda6 100644
--- a/src/cobalt/browser/application.cc
+++ b/src/cobalt/browser/application.cc
@@ -20,6 +20,7 @@
#include <vector>
#include "base/command_line.h"
+#include "base/debug/trace_event.h"
#include "base/lazy_instance.h"
#include "base/logging.h"
#include "base/path_service.h"
@@ -62,7 +63,11 @@
namespace {
const int kStatUpdatePeriodMs = 1000;
+#if defined(COBALT_BUILD_TYPE_GOLD)
+const int kLiteStatUpdatePeriodMs = 1000;
+#else
const int kLiteStatUpdatePeriodMs = 16;
+#endif
const char kDefaultURL[] = "https://www.youtube.com/tv";
@@ -320,6 +325,8 @@
FilePath(FILE_PATH_LITERAL("timed_trace.json")), trace_duration);
}
+ TRACE_EVENT0("cobalt::browser", "Application::Application()");
+
DCHECK(MessageLoop::current());
DCHECK_EQ(MessageLoop::TYPE_UI, MessageLoop::current()->type());
@@ -586,6 +593,7 @@
}
void Application::OnAccountEvent(const base::Event* event) {
+ TRACE_EVENT0("cobalt::browser", "Application::OnAccountEvent()");
const account::AccountEvent* account_event =
base::polymorphic_downcast<const account::AccountEvent*>(event);
if (account_event->type() == account::AccountEvent::kSignedIn) {
@@ -600,6 +608,7 @@
}
void Application::OnNetworkEvent(const base::Event* event) {
+ TRACE_EVENT0("cobalt::browser", "Application::OnNetworkEvent()");
DCHECK(network_event_thread_checker_.CalledOnValidThread());
const network::NetworkEvent* network_event =
base::polymorphic_downcast<const network::NetworkEvent*>(event);
@@ -620,6 +629,7 @@
}
void Application::OnApplicationEvent(const base::Event* event) {
+ TRACE_EVENT0("cobalt::browser", "Application::OnApplicationEvent()");
DCHECK(application_event_thread_checker_.CalledOnValidThread());
const system_window::ApplicationEvent* app_event =
base::polymorphic_downcast<const system_window::ApplicationEvent*>(event);
@@ -651,6 +661,7 @@
}
void Application::OnDeepLinkEvent(const base::Event* event) {
+ TRACE_EVENT0("cobalt::browser", "Application::OnDeepLinkEvent()");
const base::DeepLinkEvent* deep_link_event =
base::polymorphic_downcast<const base::DeepLinkEvent*>(event);
// TODO: Remove this when terminal application states are properly handled.
@@ -660,6 +671,7 @@
}
void Application::WebModuleRecreated() {
+ TRACE_EVENT0("cobalt::browser", "Application::WebModuleRecreated()");
#if defined(ENABLE_WEBDRIVER)
if (web_driver_module_) {
web_driver_module_->OnWindowRecreated();
@@ -741,6 +753,7 @@
}
void Application::UpdatePeriodicStats() {
+ TRACE_EVENT0("cobalt::browser", "Application::UpdatePeriodicStats()");
#if defined(__LB_SHELL__)
bool memory_stats_updated = false;
#if !defined(__LB_SHELL__FOR_RELEASE__)
diff --git a/src/cobalt/browser/browser_module.cc b/src/cobalt/browser/browser_module.cc
index e725572..9a730cc 100644
--- a/src/cobalt/browser/browser_module.cc
+++ b/src/cobalt/browser/browser_module.cc
@@ -168,11 +168,21 @@
has_resumed_(true, false),
will_quit_(false),
suspended_(false) {
+ TRACE_EVENT0("cobalt::browser", "BrowserModule::BrowserModule()");
// All allocations for media will be tracked by "Media" memory scope.
{
TRACK_MEMORY_SCOPE("Media");
+ math::Size output_size = renderer_module_.render_target()->GetSize();
+ if (system_window->GetVideoPixelRatio() != 1.f) {
+ output_size.set_width(
+ static_cast<int>(static_cast<float>(output_size.width()) *
+ system_window->GetVideoPixelRatio()));
+ output_size.set_height(
+ static_cast<int>(static_cast<float>(output_size.height()) *
+ system_window->GetVideoPixelRatio()));
+ }
media_module_ = (media::MediaModule::Create(
- system_window, renderer_module_.render_target()->GetSize(),
+ system_window, output_size,
renderer_module_.pipeline()->GetResourceProvider(),
options.media_module_options));
}
@@ -225,6 +235,7 @@
}
void BrowserModule::Navigate(const GURL& url) {
+ TRACE_EVENT0("cobalt::browser", "BrowserModule::Navigate()");
web_module_loaded_.Reset();
// Always post this as a task in case this is being called from the WebModule.
@@ -233,6 +244,7 @@
}
void BrowserModule::Reload() {
+ TRACE_EVENT0("cobalt::browser", "BrowserModule::Reload()");
DCHECK_EQ(MessageLoop::current(), self_message_loop_);
DCHECK(web_module_);
web_module_->ExecuteJavascript(
@@ -241,6 +253,7 @@
}
void BrowserModule::NavigateInternal(const GURL& url) {
+ TRACE_EVENT0("cobalt::browser", "BrowserModule::NavigateInternal()");
DCHECK_EQ(MessageLoop::current(), self_message_loop_);
// First try the registered handlers (e.g. for h5vcc://). If one of these
@@ -264,7 +277,7 @@
renderer_module_.pipeline()->GetResourceProvider(),
kLayoutMaxRefreshFrequencyInHz));
-#if defined(STARBOARD)
+#if defined(OS_STARBOARD)
#if SB_HAS(1_CORE)
// Wait until the splash screen is ready before loading the main web module.
// This prevents starvation of the splash screen module and decoding of the
@@ -312,6 +325,7 @@
}
void BrowserModule::OnLoad() {
+ TRACE_EVENT0("cobalt::browser", "BrowserModule::OnLoad()");
// Repost to our own message loop if necessary. This also prevents
// asynchonrous access to this object by |web_module_| during destruction.
if (MessageLoop::current() != self_message_loop_) {
@@ -325,6 +339,7 @@
}
bool BrowserModule::WaitForLoad(const base::TimeDelta& timeout) {
+ TRACE_EVENT0("cobalt::browser", "BrowserModule::WaitForLoad()");
return web_module_loaded_.TimedWait(timeout);
}
@@ -502,6 +517,7 @@
}
void BrowserModule::OnError(const GURL& url, const std::string& error) {
+ TRACE_EVENT0("cobalt::browser", "BrowserModule::OnError()");
LOG(ERROR) << error;
std::string url_string = "h5vcc://network-failure";
@@ -512,6 +528,7 @@
}
bool BrowserModule::FilterKeyEvent(const dom::KeyboardEvent::Data& event) {
+ TRACE_EVENT0("cobalt::browser", "BrowserModule::FilterKeyEvent()");
// Check for hotkeys first. If it is a hotkey, no more processing is needed.
if (!FilterKeyEventForHotkeys(event)) {
return false;
@@ -577,7 +594,10 @@
return false;
}
-void BrowserModule::DestroySplashScreen() { splash_screen_.reset(NULL); }
+void BrowserModule::DestroySplashScreen() {
+ TRACE_EVENT0("cobalt::browser", "BrowserModule::DestroySplashScreen()");
+ splash_screen_.reset(NULL);
+}
#if defined(ENABLE_WEBDRIVER)
scoped_ptr<webdriver::SessionDriver> BrowserModule::CreateSessionDriver(
@@ -649,6 +669,7 @@
}
void BrowserModule::Suspend() {
+ TRACE_EVENT0("cobalt::browser", "BrowserModule::Suspend()");
DCHECK_EQ(MessageLoop::current(), self_message_loop_);
DCHECK(!suspended_);
@@ -691,6 +712,7 @@
}
void BrowserModule::Resume() {
+ TRACE_EVENT0("cobalt::browser", "BrowserModule::Resume()");
DCHECK_EQ(MessageLoop::current(), self_message_loop_);
DCHECK(suspended_);
@@ -721,6 +743,8 @@
#if defined(OS_STARBOARD)
void BrowserModule::OnRendererSubmissionRasterized() {
+ TRACE_EVENT0("cobalt::browser",
+ "BrowserModule::OnRendererSubmissionRasterized()");
if (!is_rendered_) {
// Hide the system splash screen when the first render has completed.
is_rendered_ = true;
diff --git a/src/cobalt/browser/stack_size_constants.h b/src/cobalt/browser/stack_size_constants.h
index d700f4b..c4e62ea 100644
--- a/src/cobalt/browser/stack_size_constants.h
+++ b/src/cobalt/browser/stack_size_constants.h
@@ -24,8 +24,11 @@
#if defined(COBALT_BUILD_TYPE_DEBUG)
// Non-optimized builds require a bigger stack size.
const size_t kBaseStackSize = 2 * 1024 * 1024;
+#elif defined(COBALT_BUILD_TYPE_DEVEL)
+ // Devel builds require a slightly bigger stack size.
+ const size_t kBaseStackSize = 448 * 1024;
#else
- const size_t kBaseStackSize = 256 * 1024;
+ const size_t kBaseStackSize = 384 * 1024;
#endif
const size_t kWebModuleStackSize =
kBaseStackSize + base::kAsanAdditionalStackSize;
diff --git a/src/cobalt/browser/web_module.cc b/src/cobalt/browser/web_module.cc
index af93505..defb344 100644
--- a/src/cobalt/browser/web_module.cc
+++ b/src/cobalt/browser/web_module.cc
@@ -46,11 +46,11 @@
namespace {
-#if defined(COBALT_RELEASE)
+#if defined(COBALT_BUILD_TYPE_GOLD)
const int kPollerPeriodMs = 2000;
-#else // #if defined(COBALT_RELEASE)
+#else // #if defined(COBALT_BUILD_TYPE_GOLD)
const int kPollerPeriodMs = 20;
-#endif // #if defined(COBALT_RELEASE)
+#endif // #if defined(COBALT_BUILD_TYPE_GOLD)
// The maximum number of element depth in the DOM tree. Elements at a level
// deeper than this could be discarded, and will not be rendered.
@@ -147,7 +147,11 @@
void CreateDebugServerIfNull();
#endif // ENABLE_DEBUG_CONSOLE
- void Suspend();
+ // Suspension of the WebModule is a two-part process since a message loop
+ // gap is needed in order to give a chance to handle loader callbacks
+ // that were initiated from a loader thread.
+ void SuspendLoaders();
+ void FinishSuspend();
void Resume(render_tree::ResourceProvider* resource_provider);
private:
@@ -618,21 +622,20 @@
}
}
-void WebModule::Impl::Suspend() {
- TRACE_EVENT0("cobalt::browser", "WebModule::Impl::Suspend()");
- DCHECK(resource_provider_);
+void WebModule::Impl::SuspendLoaders() {
+ TRACE_EVENT0("cobalt::browser", "WebModule::Impl::SuspendLoaders()");
// Stop the generation of render trees.
layout_manager_->Suspend();
-#if defined(ENABLE_DEBUG_CONSOLE)
- // The debug overlay may be holding onto a render tree, clear that out.
- debug_overlay_->ClearInput();
-#endif
-
// Clear out the loader factory's resource provider, possibly aborting any
// in-progress loads.
loader_factory_->Suspend();
+}
+
+void WebModule::Impl::FinishSuspend() {
+ TRACE_EVENT0("cobalt::browser", "WebModule::Impl::FinishSuspend()");
+ DCHECK(resource_provider_);
// Ensure the document is not holding onto any more image cached resources so
// that they are eligible to be purged.
@@ -645,6 +648,11 @@
image_cache_->Purge();
remote_typeface_cache_->Purge();
+#if defined(ENABLE_DEBUG_CONSOLE)
+ // The debug overlay may be holding onto a render tree, clear that out.
+ debug_overlay_->ClearInput();
+#endif
+
// Finally mark that we have no resource provider.
resource_provider_ = NULL;
}
@@ -877,16 +885,43 @@
#endif // defined(ENABLE_DEBUG_CONSOLE)
void WebModule::Suspend() {
- message_loop()->PostTask(
- FROM_HERE,
- base::Bind(&WebModule::Impl::Suspend, base::Unretained(impl_.get())));
+ TRACE_EVENT0("cobalt::browser", "WebModule::Suspend()");
- base::WaitableEvent resource_provider_released(true, false);
- message_loop()->PostTask(
- FROM_HERE, base::Bind(&base::WaitableEvent::Signal,
- base::Unretained(&resource_provider_released)));
+ // Suspend() must only be called by a thread external from the WebModule
+ // thread.
+ DCHECK_NE(MessageLoop::current(), message_loop());
- resource_provider_released.Wait();
+ base::WaitableEvent task_finished(false /* automatic reset */,
+ false /* initially unsignaled */);
+
+ // Suspension of the WebModule is orchestrated here in two phases.
+ // 1) Send a signal to suspend WebModule loader activity and cancel any
+ // in-progress loads. Since loading may occur from any thread, this may
+ // result in cancel/completion callbacks being posted to message_loop().
+ message_loop()->PostTask(FROM_HERE,
+ base::Bind(&WebModule::Impl::SuspendLoaders,
+ base::Unretained(impl_.get())));
+
+ // Wait for the suspension task to complete before proceeding.
+ message_loop()->PostTask(FROM_HERE,
+ base::Bind(&base::WaitableEvent::Signal,
+ base::Unretained(&task_finished)));
+ task_finished.Wait();
+
+ // 2) Now append to the task queue a task to complete the suspension process.
+ // Between 1 and 2, tasks may have been registered to handle resource load
+ // completion events, and so this FinishSuspend task will be executed after
+ // the load completions are all resolved.
+ message_loop()->PostTask(FROM_HERE,
+ base::Bind(&WebModule::Impl::FinishSuspend,
+ base::Unretained(impl_.get())));
+
+ // Wait for suspension to fully complete on the WebModule thread before
+ // continuing.
+ message_loop()->PostTask(FROM_HERE,
+ base::Bind(&base::WaitableEvent::Signal,
+ base::Unretained(&task_finished)));
+ task_finished.Wait();
}
void WebModule::Resume(render_tree::ResourceProvider* resource_provider) {
diff --git a/src/cobalt/build/build.id b/src/cobalt/build/build.id
index 1cb6aab..e0a264e 100644
--- a/src/cobalt/build/build.id
+++ b/src/cobalt/build/build.id
@@ -1 +1 @@
-15306
\ No newline at end of file
+16000
\ No newline at end of file
diff --git a/src/cobalt/build/config/base.gypi b/src/cobalt/build/config/base.gypi
index 314650b..53cc9b4 100644
--- a/src/cobalt/build/config/base.gypi
+++ b/src/cobalt/build/config/base.gypi
@@ -67,6 +67,13 @@
# platform.
'default_renderer_options_dependency%': '<(DEPTH)/cobalt/renderer/default_options_starboard.gyp:default_options',
+ # Allow throttling of the frame rate. This is expressed in terms of
+ # milliseconds and can be a floating point number. Keep in mind that
+ # swapping frames may take some additional processing time, so it may be
+ # better to specify a lower delay. For example, '33' instead of '33.33'
+ # for 30 Hz refresh.
+ 'cobalt_minimum_frame_time_in_milliseconds%': '0',
+
# The variables allow changing the target type on platforms where the
# native code may require an additional packaging step (ex. Android).
'gtest_target_type%': 'executable',
diff --git a/src/cobalt/css_parser/css_parser.gyp b/src/cobalt/css_parser/css_parser.gyp
index 185ee0b..32f9c0d 100644
--- a/src/cobalt/css_parser/css_parser.gyp
+++ b/src/cobalt/css_parser/css_parser.gyp
@@ -111,6 +111,7 @@
'dependencies': [
'<(DEPTH)/cobalt/base/base.gyp:base',
'<(DEPTH)/cobalt/cssom/cssom.gyp:cssom',
+ '<(DEPTH)/nb/nb.gyp:nb',
'<(DEPTH)/third_party/icu/icu.gyp:icuuc',
'css_grammar',
],
diff --git a/src/cobalt/css_parser/parser.cc b/src/cobalt/css_parser/parser.cc
index 25f4d35..cb4fb84 100644
--- a/src/cobalt/css_parser/parser.cc
+++ b/src/cobalt/css_parser/parser.cc
@@ -85,6 +85,7 @@
#include "cobalt/cssom/unicode_range_value.h"
#include "cobalt/cssom/universal_selector.h"
#include "cobalt/cssom/url_value.h"
+#include "nb/memory_scope.h"
namespace cobalt {
namespace css_parser {
@@ -254,18 +255,21 @@
into_declaration_data_(NULL) {}
scoped_refptr<cssom::CSSStyleSheet> ParserImpl::ParseStyleSheet() {
+ TRACK_MEMORY_SCOPE("CSS");
scanner_.PrependToken(kStyleSheetEntryPointToken);
return Parse() ? style_sheet_
: make_scoped_refptr(new cssom::CSSStyleSheet(css_parser_));
}
scoped_refptr<cssom::CSSRule> ParserImpl::ParseRule() {
+ TRACK_MEMORY_SCOPE("CSS");
scanner_.PrependToken(kRuleEntryPointToken);
return Parse() ? rule_ : NULL;
}
scoped_refptr<cssom::CSSDeclaredStyleData>
ParserImpl::ParseStyleDeclarationList() {
+ TRACK_MEMORY_SCOPE("CSS");
scanner_.PrependToken(kStyleDeclarationListEntryPointToken);
return Parse() ? style_declaration_data_
: make_scoped_refptr(new cssom::CSSDeclaredStyleData());
@@ -273,6 +277,7 @@
scoped_refptr<cssom::CSSFontFaceDeclarationData>
ParserImpl::ParseFontFaceDeclarationList() {
+ TRACK_MEMORY_SCOPE("CSS");
scanner_.PrependToken(kFontFaceDeclarationListEntryPointToken);
return Parse() ? font_face_declaration_data_
: make_scoped_refptr(new cssom::CSSFontFaceDeclarationData());
@@ -290,6 +295,7 @@
scoped_refptr<cssom::PropertyValue> ParserImpl::ParsePropertyValue(
const std::string& property_name) {
+ TRACK_MEMORY_SCOPE("CSS");
Token property_name_token;
bool is_property_name_known =
scanner_.DetectPropertyNameToken(property_name, &property_name_token);
@@ -312,6 +318,7 @@
void ParserImpl::ParsePropertyIntoDeclarationData(
const std::string& property_name,
cssom::CSSDeclarationData* declaration_data) {
+ TRACK_MEMORY_SCOPE("CSS");
Token property_name_token;
bool is_property_name_known =
scanner_.DetectPropertyNameToken(property_name, &property_name_token);
@@ -340,11 +347,13 @@
}
scoped_refptr<cssom::MediaList> ParserImpl::ParseMediaList() {
+ TRACK_MEMORY_SCOPE("CSS");
scanner_.PrependToken(kMediaListEntryPointToken);
return Parse() ? media_list_ : make_scoped_refptr(new cssom::MediaList());
}
scoped_refptr<cssom::MediaQuery> ParserImpl::ParseMediaQuery() {
+ TRACK_MEMORY_SCOPE("CSS");
scanner_.PrependToken(kMediaQueryEntryPointToken);
return Parse() ? media_query_ : make_scoped_refptr(new cssom::MediaQuery());
}
@@ -364,6 +373,7 @@
}
bool ParserImpl::Parse() {
+ TRACK_MEMORY_SCOPE("CSS");
// For more information on error codes
// see http://www.gnu.org/software/bison/manual/html_node/Parser-Function.html
TRACE_EVENT0("cobalt::css_parser", "ParseImpl::Parse");
diff --git a/src/cobalt/dom/media_source.cc b/src/cobalt/dom/media_source.cc
index 83bc8c0..9807b48 100644
--- a/src/cobalt/dom/media_source.cc
+++ b/src/cobalt/dom/media_source.cc
@@ -21,6 +21,7 @@
#include <vector>
#include "base/compiler_specific.h"
+#include "base/debug/trace_event.h"
#include "base/hash_tables.h"
#include "base/lazy_instance.h"
#include "base/logging.h"
@@ -303,6 +304,8 @@
SetReadyState(kReadyStateOpen);
}
+ TRACE_EVENT1("media_stack", "MediaSource::Append()", "size", size);
+
// If size is greater than kMaxAppendSize, we will append the data in multiple
// small chunks with size less than or equal to kMaxAppendSize. This can
// avoid memory allocation spike as ChunkDemuxer may try to allocator memory
diff --git a/src/cobalt/layout/box.cc b/src/cobalt/layout/box.cc
index 4426498..a04ced7 100644
--- a/src/cobalt/layout/box.cc
+++ b/src/cobalt/layout/box.cc
@@ -16,6 +16,7 @@
#include "cobalt/layout/box.h"
+#include <algorithm>
#include <limits>
#include "base/logging.h"
@@ -907,7 +908,7 @@
style->opacity().get())->value();
if (opacity < 1.0f) {
- filter_node_builder->opacity_filter.emplace(opacity);
+ filter_node_builder->opacity_filter.emplace(std::max(0.0f, opacity));
} else {
// If opacity is 1, then no opacity filter should be applied, so the
// source render tree should appear fully opaque.
@@ -1155,7 +1156,7 @@
FilterNode::Builder filter_node_builder(border_node);
if (opacity < 1.0f) {
- filter_node_builder.opacity_filter = OpacityFilter(opacity);
+ filter_node_builder.opacity_filter.emplace(std::max(0.0f, opacity));
}
scoped_refptr<FilterNode> filter_node = new FilterNode(filter_node_builder);
diff --git a/src/cobalt/layout_tests/layout_tests.cc b/src/cobalt/layout_tests/layout_tests.cc
index 18dccb1..38adb86 100644
--- a/src/cobalt/layout_tests/layout_tests.cc
+++ b/src/cobalt/layout_tests/layout_tests.cc
@@ -189,6 +189,11 @@
AnimationTimingAPILayoutTests, LayoutTest,
::testing::ValuesIn(EnumerateLayoutTests("animation-timing")));
+// Problematic test cases found through cluster-fuzz.
+INSTANTIATE_TEST_CASE_P(
+ ClusterFuzzLayoutTests, LayoutTest,
+ ::testing::ValuesIn(EnumerateLayoutTests("cluster-fuzz")));
+
// Disable on Windows until network stack is implemented.
#if !defined(COBALT_WIN)
// Content Security Policy test cases.
diff --git a/src/cobalt/layout_tests/testdata/cluster-fuzz/fuzz-222-expected.png b/src/cobalt/layout_tests/testdata/cluster-fuzz/fuzz-222-expected.png
new file mode 100644
index 0000000..f1b767f
--- /dev/null
+++ b/src/cobalt/layout_tests/testdata/cluster-fuzz/fuzz-222-expected.png
Binary files differ
diff --git a/src/cobalt/layout_tests/testdata/cluster-fuzz/fuzz-222.html b/src/cobalt/layout_tests/testdata/cluster-fuzz/fuzz-222.html
new file mode 100644
index 0000000..9f6ed1a
--- /dev/null
+++ b/src/cobalt/layout_tests/testdata/cluster-fuzz/fuzz-222.html
@@ -0,0 +1,17 @@
+cm/000000086.jpg" target="_blank"><img src="./picm/000000086.jpg" width="277" style="border: 0px solid ;"></a>
+<div class="blockImageCaption"><br>�s�d�k�F�i�O�W�V�j�W�V�W�|�Q�P�W�W�i���j<br>�e�`�w�F�i�O�W�V�j�W�V�W�|�Q�V�V�P</p>
+<!-- -->
+<!-- /blockText --></div>
+<!-- -->
+<!-- /blockText --></div>
+<!-- /block2column2 --></div>
+<br class="blockEdge">
+<!-- /CB0200_4 --></div>
+>
+<!-- -->
+
+<!-- --><div class="blockImage">
+<!-- -->
+ class="blockImageCaption"><small></small></div>
+>
+<!--
\ No newline at end of file
diff --git a/src/cobalt/layout_tests/testdata/cluster-fuzz/layout_tests.txt b/src/cobalt/layout_tests/testdata/cluster-fuzz/layout_tests.txt
new file mode 100644
index 0000000..12a4567
--- /dev/null
+++ b/src/cobalt/layout_tests/testdata/cluster-fuzz/layout_tests.txt
@@ -0,0 +1 @@
+fuzz-222
\ No newline at end of file
diff --git a/src/cobalt/loader/embedded_resources/splash_screen.css b/src/cobalt/loader/embedded_resources/splash_screen.css
index 7602576..3cba6e4 100644
--- a/src/cobalt/loader/embedded_resources/splash_screen.css
+++ b/src/cobalt/loader/embedded_resources/splash_screen.css
@@ -22,13 +22,12 @@
width: 100%;
}
-@keyframes loadwait {
- 0% {opacity: 0}
- 100% {opacity: 1}
-}
-
#spinner {
- animation: loadwait 2s steps(1, end);
+ /* The spinner starts with display set to none, and JavaScript will set this
+ to 'block' after some time has passed, if the splash screen is still
+ visible. */
+ display: none;
+
height: 5.33em;
margin: 0 auto;
position: relative;
diff --git a/src/cobalt/loader/embedded_resources/splash_screen.html b/src/cobalt/loader/embedded_resources/splash_screen.html
index 2a572ed..0e57e3b 100644
--- a/src/cobalt/loader/embedded_resources/splash_screen.html
+++ b/src/cobalt/loader/embedded_resources/splash_screen.html
@@ -3,8 +3,9 @@
<head>
<meta http-equiv="Content-Security-Policy" content="default-src 'none';
+ script-src h5vcc-embedded://*/splash_screen.js;
style-src h5vcc-embedded://*/splash_screen.css;
- img-src h5vcc-embedded://*/you_tube_logo.png">
+ img-src h5vcc-embedded://*/you_tube_logo.png;">
<link rel="stylesheet" type="text/css" href="h5vcc-embedded://splash_screen.css">
</head>
@@ -24,6 +25,8 @@
<div class="dot" id="dot8"></div>
</div>
</div>
+ <script type="text/javascript" src="h5vcc-embedded://splash_screen.js">
+ </script>
</body>
</html>
diff --git a/src/cobalt/loader/embedded_resources/splash_screen.js b/src/cobalt/loader/embedded_resources/splash_screen.js
new file mode 100644
index 0000000..0d30edc
--- /dev/null
+++ b/src/cobalt/loader/embedded_resources/splash_screen.js
@@ -0,0 +1,5 @@
+ // Enable the spinner after 3 seconds have passed.
+ window.setTimeout(function() {
+ var spinner = document.getElementById('spinner');
+ spinner.style.display = 'block';
+ }, 3000);
diff --git a/src/cobalt/loader/image/image_decoder.cc b/src/cobalt/loader/image/image_decoder.cc
index 6fcf6ec..5a55b9c 100644
--- a/src/cobalt/loader/image/image_decoder.cc
+++ b/src/cobalt/loader/image/image_decoder.cc
@@ -99,6 +99,7 @@
failure_callback_(failure_callback),
error_callback_(error_callback),
state_(kWaitingForHeader) {
+ TRACE_EVENT0("cobalt::loader::image", "ImageDecoder::ImageDecoder()");
signature_cache_.position = 0;
if (!resource_provider_) {
@@ -109,6 +110,7 @@
LoadResponseType ImageDecoder::OnResponseStarted(
Fetcher* fetcher, const scoped_refptr<net::HttpResponseHeaders>& headers) {
UNREFERENCED_PARAMETER(fetcher);
+ TRACE_EVENT0("cobalt::loader::image", "ImageDecoder::OnResponseStarted()");
if (state_ == kSuspended) {
DLOG(WARNING) << __FUNCTION__ << "[" << this << "] while suspended.";
@@ -202,6 +204,7 @@
}
bool ImageDecoder::Suspend() {
+ TRACE_EVENT0("cobalt::loader::image", "ImageDecoder::Suspend()");
if (state_ == kDecoding) {
DCHECK(decoder_);
decoder_.reset();
@@ -213,6 +216,7 @@
}
void ImageDecoder::Resume(render_tree::ResourceProvider* resource_provider) {
+ TRACE_EVENT0("cobalt::loader::image", "ImageDecoder::Resume()");
if (state_ != kSuspended) {
DCHECK_EQ(resource_provider_, resource_provider);
return;
@@ -227,6 +231,7 @@
}
void ImageDecoder::DecodeChunkInternal(const uint8* input_bytes, size_t size) {
+ TRACE_EVENT0("cobalt::loader::image", "ImageDecoder::DecodeChunkInternal()");
switch (state_) {
case kWaitingForHeader: {
size_t consumed_size = 0;
@@ -263,6 +268,8 @@
bool ImageDecoder::InitializeInternalDecoder(const uint8* input_bytes,
size_t size,
size_t* consumed_size) {
+ TRACE_EVENT0("cobalt::loader::image",
+ "ImageDecoder::InitializeInternalDecoder()");
const size_t index = signature_cache_.position;
size_t fill_size = std::min(kLengthOfLongestSignature - index, size);
memcpy(signature_cache_.data + index, input_bytes, fill_size);
diff --git a/src/cobalt/loader/image/image_decoder_starboard.cc b/src/cobalt/loader/image/image_decoder_starboard.cc
index 5a90442..1fdb7bf 100644
--- a/src/cobalt/loader/image/image_decoder_starboard.cc
+++ b/src/cobalt/loader/image/image_decoder_starboard.cc
@@ -38,17 +38,25 @@
mime_type_(mime_type),
format_(format),
provider_(resource_provider->GetSbDecodeTargetProvider()),
- target_(kSbDecodeTargetInvalid) {}
+ target_(kSbDecodeTargetInvalid) {
+ TRACE_EVENT0("cobalt::loader::image",
+ "ImageDecoderStarboard::ImageDecoderStarboard()");
+}
ImageDecoderStarboard::~ImageDecoderStarboard() {}
size_t ImageDecoderStarboard::DecodeChunkInternal(const uint8* data,
size_t input_byte) {
+ TRACE_EVENT0("cobalt::loader::image",
+ "ImageDecoderStarboard::DecodeChunkInternal()");
+
buffer_.insert(buffer_.end(), data, data + input_byte);
return input_byte;
}
void ImageDecoderStarboard::FinishInternal() {
+ TRACE_EVENT0("cobalt::loader::image",
+ "ImageDecoderStarboard::FinishInternal()");
DCHECK(!buffer_.empty());
DCHECK(SbImageIsDecodeSupported(mime_type_, format_));
target_ =
diff --git a/src/cobalt/loader/image/jpeg_image_decoder.cc b/src/cobalt/loader/image/jpeg_image_decoder.cc
index 6fe1d91..29b99dc 100644
--- a/src/cobalt/loader/image/jpeg_image_decoder.cc
+++ b/src/cobalt/loader/image/jpeg_image_decoder.cc
@@ -84,6 +84,7 @@
JPEGImageDecoder::JPEGImageDecoder(
render_tree::ResourceProvider* resource_provider)
: ImageDataDecoder(resource_provider) {
+ TRACE_EVENT0("cobalt::loader::image", "JPEGImageDecoder::JPEGImageDecoder()");
memset(&info_, 0, sizeof(info_));
memset(&source_manager_, 0, sizeof(source_manager_));
@@ -111,6 +112,8 @@
size_t JPEGImageDecoder::DecodeChunkInternal(const uint8* data,
size_t input_byte) {
+ TRACE_EVENT0("cobalt::loader::image",
+ "JPEGImageDecoder::DecodeChunkInternal()");
// |client_data| is available for use by application.
jmp_buf jump_buffer;
info_.client_data = &jump_buffer;
@@ -175,6 +178,7 @@
}
bool JPEGImageDecoder::ReadHeader() {
+ TRACE_EVENT0("cobalt::loader::image", "JPEGImageDecoder::ReadHeader()");
if (jpeg_read_header(&info_, true) == JPEG_SUSPENDED) {
// Since |jpeg_read_header| doesn't have enough data, go back to the state
// before reading the header.
@@ -189,6 +193,7 @@
}
bool JPEGImageDecoder::StartDecompress() {
+ TRACE_EVENT0("cobalt::loader::image", "JPEGImageDecoder::StartDecompress()");
// jpeg_has_multiple_scans() returns TRUE if the incoming image file has more
// than one scan.
info_.buffered_image = jpeg_has_multiple_scans(&info_);
@@ -215,6 +220,8 @@
// TODO: support displaying the low resolution image while decoding
// the progressive JPEG.
bool JPEGImageDecoder::DecodeProgressiveJPEG() {
+ TRACE_EVENT0("cobalt::loader::image",
+ "JPEGImageDecoder::DecodeProgressiveJPEG()");
int status;
do {
// |jpeg_consume_input| decodes the input data as it arrives.
@@ -291,6 +298,8 @@
}
bool JPEGImageDecoder::ReadLines() {
+ TRACE_EVENT0("cobalt::loader::image", "JPEGImageDecoder::ReadLines()");
+
// Creation of 2-D sample arrays which is for one row.
// See the comments in jmemmgr.c.
JSAMPARRAY buffer = (*info_.mem->alloc_sarray)(
diff --git a/src/cobalt/loader/image/png_image_decoder.cc b/src/cobalt/loader/image/png_image_decoder.cc
index e87eeb9..b09e637 100644
--- a/src/cobalt/loader/image/png_image_decoder.cc
+++ b/src/cobalt/loader/image/png_image_decoder.cc
@@ -16,6 +16,7 @@
#include "cobalt/loader/image/png_image_decoder.h"
+#include "base/debug/trace_event.h"
#include "base/logging.h"
namespace cobalt {
@@ -72,6 +73,8 @@
info_(NULL),
has_alpha_(false),
interlace_buffer_(0) {
+ TRACE_EVENT0("cobalt::loader::image", "PNGImageDecoder::PNGImageDecoder()");
+
png_ = png_create_read_struct(PNG_LIBPNG_VER_STRING, 0, DecodingFailed,
DecodingWarning);
info_ = png_create_info_struct(png_);
@@ -80,6 +83,8 @@
}
size_t PNGImageDecoder::DecodeChunkInternal(const uint8* data, size_t size) {
+ TRACE_EVENT0("cobalt::loader::image",
+ "PNGImageDecoder::DecodeChunkInternal()");
// int setjmp(jmp_buf env) saves the current environment (ths program state),
// at some point of program execution, into a platform-specific data
// structure (jmp_buf) that can be used at some later point of program
@@ -107,6 +112,7 @@
}
PNGImageDecoder::~PNGImageDecoder() {
+ TRACE_EVENT0("cobalt::loader::image", "PNGImageDecoder::~PNGImageDecoder()");
// Both are created at the same time. So they should be both zero
// or both non-zero. Use && here to be safer.
if (png_ && info_) {
@@ -127,6 +133,7 @@
// static
void PNGImageDecoder::HeaderAvailable(png_structp png, png_infop info) {
UNREFERENCED_PARAMETER(info);
+ TRACE_EVENT0("cobalt::loader::image", "PNGImageDecoder::~PNGImageDecoder()");
PNGImageDecoder* decoder =
static_cast<PNGImageDecoder*>(png_get_progressive_ptr(png));
decoder->HeaderAvailableCallback();
@@ -146,12 +153,16 @@
// static
void PNGImageDecoder::DecodeDone(png_structp png, png_infop info) {
UNREFERENCED_PARAMETER(info);
+ TRACE_EVENT0("cobalt::loader::image", "PNGImageDecoder::DecodeDone()");
+
PNGImageDecoder* decoder =
static_cast<PNGImageDecoder*>(png_get_progressive_ptr(png));
decoder->DecodeDoneCallback();
}
void PNGImageDecoder::HeaderAvailableCallback() {
+ TRACE_EVENT0("cobalt::loader::image",
+ "PNGImageDecoder::HeaderAvailableCallback()");
DCHECK_EQ(state(), kWaitingForHeader);
png_uint_32 width = png_get_image_width(png_, info_);
diff --git a/src/cobalt/loader/image/webp_image_decoder.cc b/src/cobalt/loader/image/webp_image_decoder.cc
index 53f24eb..cff8594 100644
--- a/src/cobalt/loader/image/webp_image_decoder.cc
+++ b/src/cobalt/loader/image/webp_image_decoder.cc
@@ -16,6 +16,7 @@
#include "cobalt/loader/image/webp_image_decoder.h"
+#include "base/debug/trace_event.h"
#include "base/logging.h"
namespace cobalt {
@@ -25,6 +26,7 @@
WEBPImageDecoder::WEBPImageDecoder(
render_tree::ResourceProvider* resource_provider)
: ImageDataDecoder(resource_provider), internal_decoder_(NULL) {
+ TRACE_EVENT0("cobalt::loader::image", "WEBPImageDecoder::WEBPImageDecoder()");
// Initialize the configuration as empty.
WebPInitDecoderConfig(&config_);
// Skip the in-loop filtering.
@@ -37,10 +39,16 @@
config_.options.no_enhancement = 1;
}
-WEBPImageDecoder::~WEBPImageDecoder() { DeleteInternalDecoder(); }
+WEBPImageDecoder::~WEBPImageDecoder() {
+ TRACE_EVENT0("cobalt::loader::image",
+ "WEBPImageDecoder::~WEBPImageDecoder()");
+ DeleteInternalDecoder();
+}
size_t WEBPImageDecoder::DecodeChunkInternal(const uint8* data,
size_t input_byte) {
+ TRACE_EVENT0("cobalt::loader::image",
+ "WEBPImageDecoder::DecodeChunkInternal()");
const uint8* next_input_byte = data;
size_t bytes_in_buffer = input_byte;
@@ -81,6 +89,7 @@
bool WEBPImageDecoder::ReadHeader(const uint8* data, size_t size,
bool* has_alpha) {
+ TRACE_EVENT0("cobalt::loader::image", "WEBPImageDecoder::ReadHeader()");
// Retrieve features from the bitstream. The *features structure is filled
// with information gathered from the bitstream.
// Returns VP8_STATUS_OK when the features are successfully retrieved. Returns
@@ -105,6 +114,8 @@
}
bool WEBPImageDecoder::CreateInternalDecoder(bool has_alpha) {
+ TRACE_EVENT0("cobalt::loader::image",
+ "WEBPImageDecoder::CreateInternalDecoder()");
config_.output.colorspace = has_alpha ? MODE_rgbA : MODE_RGBA;
config_.output.u.RGBA.stride = image_data()->GetDescriptor().pitch_in_bytes;
config_.output.u.RGBA.size =
@@ -127,6 +138,8 @@
}
void WEBPImageDecoder::DeleteInternalDecoder() {
+ TRACE_EVENT0("cobalt::loader::image",
+ "WEBPImageDecoder::DeleteInternalDecoder()");
if (internal_decoder_) {
// Deletes the WebPIDecoder object and associated memory. Must always be
// called if WebPIDecode succeeded.
diff --git a/src/cobalt/loader/sync_loader.cc b/src/cobalt/loader/sync_loader.cc
index 1d0d116..7ceff82 100644
--- a/src/cobalt/loader/sync_loader.cc
+++ b/src/cobalt/loader/sync_loader.cc
@@ -18,6 +18,7 @@
#include "base/bind.h"
#include "base/compiler_specific.h"
+#include "base/debug/trace_event.h"
#include "base/synchronization/waitable_event.h"
namespace cobalt {
@@ -117,6 +118,7 @@
base::Callback<scoped_ptr<Fetcher>(Fetcher::Handler*)> fetcher_creator,
base::Callback<scoped_ptr<Decoder>()> decoder_creator,
base::Callback<void(const std::string&)> error_callback) {
+ TRACE_EVENT0("cobalt::loader", "LoadSynchronously()");
DCHECK(message_loop);
DCHECK(!error_callback.is_null());
diff --git a/src/cobalt/math/cubic_bezier.cc b/src/cobalt/math/cubic_bezier.cc
index 17c8368..51b5df0 100644
--- a/src/cobalt/math/cubic_bezier.cc
+++ b/src/cobalt/math/cubic_bezier.cc
@@ -66,8 +66,10 @@
}
// We should have terminated the above loop because we got close to x, not
- // because we exceeded MAX_STEPS. Do a DCHECK here to confirm.
- DCHECK_GT(kBezierEpsilon, std::abs(eval_bezier(x1, x2, t) - x));
+ // because we exceeded MAX_STEPS. Warn if this is not the case.
+ if (std::abs(eval_bezier(x1, x2, t) - x) > kBezierEpsilon) {
+ DLOG(WARNING) << "Notable error detected in bezier evaluation.";
+ }
return t;
}
diff --git a/src/cobalt/media/media.gyp b/src/cobalt/media/media.gyp
index 70c6929..ed7dc27 100644
--- a/src/cobalt/media/media.gyp
+++ b/src/cobalt/media/media.gyp
@@ -35,6 +35,7 @@
'dependencies': [
'<(DEPTH)/cobalt/network/network.gyp:network',
'<(DEPTH)/media/media.gyp:media',
+ '<(DEPTH)/nb/nb.gyp:nb',
],
'export_dependent_settings': [
'<(DEPTH)/media/media.gyp:media',
@@ -46,9 +47,6 @@
'shell_media_platform_<(sb_media_platform).cc',
'shell_media_platform_<(sb_media_platform).h',
],
- 'dependencies': [
- '<(DEPTH)/nb/nb.gyp:nb',
- ],
}],
['OS=="starboard" and sb_media_platform == "ps4"', {
'sources': [
@@ -72,9 +70,6 @@
'shell_media_platform_ps3.cc',
'shell_media_platform_ps3.h',
],
- 'dependencies': [
- '<(DEPTH)/nb/nb.gyp:nb',
- ],
}],
],
},
diff --git a/src/cobalt/renderer/backend/egl/display.cc b/src/cobalt/renderer/backend/egl/display.cc
index dc325c7..c294168 100644
--- a/src/cobalt/renderer/backend/egl/display.cc
+++ b/src/cobalt/renderer/backend/egl/display.cc
@@ -54,6 +54,16 @@
surface_ = eglCreateWindowSurface(display_, config_, native_window_, NULL);
CHECK_EQ(EGL_SUCCESS, eglGetError());
+ // Configure the surface to preserve contents on swap.
+ EGLBoolean surface_attrib_set =
+ eglSurfaceAttrib(display_, surface_,
+ EGL_SWAP_BEHAVIOR, EGL_BUFFER_PRESERVED);
+ // NOTE: Must check eglGetError() to clear any error flags and also check
+ // the return value of eglSurfaceAttrib since some implementations may not
+ // set the error condition.
+ content_preserved_on_swap_ =
+ eglGetError() == EGL_SUCCESS && surface_attrib_set == EGL_TRUE;
+
// Query and cache information about the surface now that we have created it.
EGLint egl_surface_width;
EGLint egl_surface_height;
diff --git a/src/cobalt/renderer/backend/egl/graphics_system.cc b/src/cobalt/renderer/backend/egl/graphics_system.cc
index 16b5104..d8895bd 100644
--- a/src/cobalt/renderer/backend/egl/graphics_system.cc
+++ b/src/cobalt/renderer/backend/egl/graphics_system.cc
@@ -64,23 +64,35 @@
// Setup our configuration to support RGBA and compatibility with PBuffer
// objects (for offscreen rendering).
- EGLint const attribute_list[] = {EGL_RED_SIZE,
- 8,
- EGL_GREEN_SIZE,
- 8,
- EGL_BLUE_SIZE,
- 8,
- EGL_ALPHA_SIZE,
- 8,
- EGL_SURFACE_TYPE,
- EGL_WINDOW_BIT | EGL_PBUFFER_BIT,
- EGL_BIND_TO_TEXTURE_RGBA,
- EGL_TRUE,
- EGL_NONE};
+ EGLint attribute_list[] = {EGL_SURFACE_TYPE, // this must be first
+ EGL_WINDOW_BIT | EGL_PBUFFER_BIT |
+ EGL_SWAP_BEHAVIOR_PRESERVED_BIT,
+ EGL_RED_SIZE,
+ 8,
+ EGL_GREEN_SIZE,
+ 8,
+ EGL_BLUE_SIZE,
+ 8,
+ EGL_ALPHA_SIZE,
+ 8,
+ EGL_BIND_TO_TEXTURE_RGBA,
+ EGL_TRUE,
+ EGL_NONE};
+
+ // Try to allow preservation of the frame contents between swap calls --
+ // this will allow rendering of only parts of the frame that have changed.
+ DCHECK_EQ(EGL_SURFACE_TYPE, attribute_list[0]);
+ EGLint& surface_type_value = attribute_list[1];
EGLint num_configs;
- EGL_CALL(
- eglChooseConfig(display_, attribute_list, &config_, 1, &num_configs));
+ eglChooseConfig(display_, attribute_list, &config_, 1, &num_configs);
+ if (eglGetError() != EGL_SUCCESS || num_configs == 0) {
+ // Swap buffer preservation may not be supported. Try to find a config
+ // without the feature.
+ surface_type_value &= ~EGL_SWAP_BEHAVIOR_PRESERVED_BIT;
+ EGL_CALL(
+ eglChooseConfig(display_, attribute_list, &config_, 1, &num_configs));
+ }
DCHECK_EQ(1, num_configs);
#if defined(GLES3_SUPPORTED)
diff --git a/src/cobalt/renderer/backend/egl/render_target.h b/src/cobalt/renderer/backend/egl/render_target.h
index d88c385..9256372 100644
--- a/src/cobalt/renderer/backend/egl/render_target.h
+++ b/src/cobalt/renderer/backend/egl/render_target.h
@@ -27,7 +27,11 @@
class RenderTargetEGL : public RenderTarget {
public:
- RenderTargetEGL() : swap_count_(0), has_been_made_current_(false) {}
+ RenderTargetEGL()
+ : swap_count_(0)
+ , has_been_made_current_(false)
+ , content_preserved_on_swap_(false)
+ {}
// An EGLSurface is needed for the EGL function eglMakeCurrent() which
// associates a render target with a rendering context.
@@ -40,6 +44,10 @@
virtual bool IsWindowRenderTarget() const { return false; }
+ // Returns whether the render target contents are preserved after the
+ // target has been displayed via eglSwapBuffers().
+ bool IsContentPreservedOnSwap() const { return content_preserved_on_swap_; }
+
int64 swap_count() { return swap_count_; }
void increment_swap_count() { ++swap_count_; }
@@ -51,6 +59,7 @@
int64 swap_count_;
bool has_been_made_current_;
+ bool content_preserved_on_swap_;
};
} // namespace backend
diff --git a/src/cobalt/renderer/frame_rate_throttler.cc b/src/cobalt/renderer/frame_rate_throttler.cc
new file mode 100644
index 0000000..20d662e
--- /dev/null
+++ b/src/cobalt/renderer/frame_rate_throttler.cc
@@ -0,0 +1,47 @@
+/*
+ * Copyright 2016 Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "cobalt/renderer/frame_rate_throttler.h"
+
+#include "base/threading/platform_thread.h"
+
+namespace cobalt {
+namespace renderer {
+
+void FrameRateThrottler::BeginInterval() {
+ if (COBALT_MINIMUM_FRAME_TIME_IN_MILLISECONDS > 0) {
+ begin_time_ = base::TimeTicks::HighResNow();
+ }
+}
+
+void FrameRateThrottler::EndInterval() {
+ // Throttle presentation of new frames if a minimum frame time is specified.
+ if (COBALT_MINIMUM_FRAME_TIME_IN_MILLISECONDS > 0) {
+ if (!begin_time_.is_null()) {
+ base::TimeDelta elapsed = base::TimeTicks::HighResNow() - begin_time_;
+ base::TimeDelta wait_time =
+ base::TimeDelta::FromMillisecondsD(
+ COBALT_MINIMUM_FRAME_TIME_IN_MILLISECONDS) -
+ elapsed;
+ if (wait_time > base::TimeDelta::FromMicroseconds(0)) {
+ base::PlatformThread::Sleep(wait_time);
+ }
+ }
+ }
+}
+
+} // namespace renderer
+} // namespace cobalt
diff --git a/src/cobalt/renderer/frame_rate_throttler.h b/src/cobalt/renderer/frame_rate_throttler.h
new file mode 100644
index 0000000..6af2be7
--- /dev/null
+++ b/src/cobalt/renderer/frame_rate_throttler.h
@@ -0,0 +1,44 @@
+/*
+ * Copyright 2016 Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef COBALT_RENDERER_FRAME_RATE_THROTTLER_H_
+#define COBALT_RENDERER_FRAME_RATE_THROTTLER_H_
+
+#include "base/time.h"
+
+namespace cobalt {
+namespace renderer {
+
+// The FrameRateThrottler is used to enforce a minimum frame time. The
+// rasterizer should call the provided hooks just before and after submitting
+// a new frame. This can be used to throttle the frame rate (to 30 Hz for
+// example) when the presentation interval cannot be specified.
+class FrameRateThrottler {
+ public:
+ // To be called just after submitting a new frame.
+ void BeginInterval();
+
+ // To be called just before submitting a new frame.
+ void EndInterval();
+
+ private:
+ base::TimeTicks begin_time_;
+};
+
+} // namespace renderer
+} // namespace cobalt
+
+#endif // COBALT_RENDERER_FRAME_RATE_THROTTLER_H_
diff --git a/src/cobalt/renderer/pipeline.cc b/src/cobalt/renderer/pipeline.cc
index 0056361..58d850b 100644
--- a/src/cobalt/renderer/pipeline.cc
+++ b/src/cobalt/renderer/pipeline.cc
@@ -74,9 +74,6 @@
submission_disposal_thread_("Rasterizer Submission Disposal"),
submit_even_if_render_tree_is_unchanged_(
submit_even_if_render_tree_is_unchanged),
- rasterize_current_tree_interval_timer_(
- "Renderer.Rasterize.Interval",
- kRasterizeCurrentTreeTimerTimeIntervalInMs),
rasterize_current_tree_timer_("Renderer.Rasterize.Duration",
kRasterizeCurrentTreeTimerTimeIntervalInMs)
#if defined(ENABLE_DEBUG_CONSOLE)
@@ -239,7 +236,6 @@
return;
}
- rasterize_current_tree_interval_timer_.Start(now);
rasterize_current_tree_timer_.Start(now);
// Rasterize the last submitted render tree.
diff --git a/src/cobalt/renderer/pipeline.h b/src/cobalt/renderer/pipeline.h
index 3b96cc3..d3a2e96 100644
--- a/src/cobalt/renderer/pipeline.h
+++ b/src/cobalt/renderer/pipeline.h
@@ -185,10 +185,8 @@
// The submission time used during the last render tree render.
base::optional<base::TimeDelta> last_render_time_;
- // Timers for tracking how frequently |RasterizeCurrentTree| is called and
- // the amount of time spent in |RasterizeCurrentTree| each call.
- base::CValTimeIntervalTimer<base::CValPublic>
- rasterize_current_tree_interval_timer_;
+ // Timer tracking the amount of time spent in |RasterizeCurrentTree| each
+ // call.
base::CValTimeIntervalTimer<base::CValPublic> rasterize_current_tree_timer_;
#if defined(ENABLE_DEBUG_CONSOLE)
diff --git a/src/cobalt/renderer/rasterizer/blitter/cached_software_rasterizer.cc b/src/cobalt/renderer/rasterizer/blitter/cached_software_rasterizer.cc
index bcb25db..5e65c9c 100644
--- a/src/cobalt/renderer/rasterizer/blitter/cached_software_rasterizer.cc
+++ b/src/cobalt/renderer/rasterizer/blitter/cached_software_rasterizer.cc
@@ -117,7 +117,7 @@
surface_map_.erase(found);
surface_map_.insert(to_insert);
- cache_frame_usage_ += found->second.GetEstimatedMemoryUsage();
+ cache_frame_usage_ += to_insert.second.GetEstimatedMemoryUsage();
return to_insert.second;
}
diff --git a/src/cobalt/renderer/rasterizer/blitter/hardware_rasterizer.cc b/src/cobalt/renderer/rasterizer/blitter/hardware_rasterizer.cc
index 7c9304e..cfca7ab 100644
--- a/src/cobalt/renderer/rasterizer/blitter/hardware_rasterizer.cc
+++ b/src/cobalt/renderer/rasterizer/blitter/hardware_rasterizer.cc
@@ -26,6 +26,7 @@
#include "cobalt/render_tree/resource_provider_stub.h"
#include "cobalt/renderer/backend/blitter/graphics_context.h"
#include "cobalt/renderer/backend/blitter/render_target.h"
+#include "cobalt/renderer/frame_rate_throttler.h"
#include "cobalt/renderer/rasterizer/blitter/cached_software_rasterizer.h"
#include "cobalt/renderer/rasterizer/blitter/render_state.h"
#include "cobalt/renderer/rasterizer/blitter/render_tree_node_visitor.h"
@@ -80,6 +81,8 @@
CachedSoftwareRasterizer software_surface_cache_;
+ FrameRateThrottler frame_rate_throttler_;
+
#if defined(ENABLE_DEBUG_CONSOLE)
// Debug command to toggle cache highlights to help visualize which nodes
// are being cached.
@@ -219,7 +222,9 @@
SbBlitterMakeRect(0, 0, width, height),
SbBlitterMakeRect(0, 0, width, height)));
CHECK(SbBlitterFlushContext(context));
+ frame_rate_throttler_.EndInterval();
render_target_blitter->Flip();
+ frame_rate_throttler_.BeginInterval();
++submit_count_;
}
diff --git a/src/cobalt/renderer/rasterizer/blitter/render_tree_node_visitor.cc b/src/cobalt/renderer/rasterizer/blitter/render_tree_node_visitor.cc
index 8fc3821..47dcf43 100644
--- a/src/cobalt/renderer/rasterizer/blitter/render_tree_node_visitor.cc
+++ b/src/cobalt/renderer/rasterizer/blitter/render_tree_node_visitor.cc
@@ -17,6 +17,7 @@
#include "cobalt/renderer/rasterizer/blitter/render_tree_node_visitor.h"
#include "base/bind.h"
+#include "base/debug/trace_event.h"
#include "cobalt/base/polymorphic_downcast.h"
#include "cobalt/math/matrix3_f.h"
#include "cobalt/math/rect.h"
@@ -33,6 +34,17 @@
#if SB_HAS(BLITTER)
+// This define exists so that developers can quickly toggle it temporarily and
+// obtain trace results for the render tree visit process here. In general
+// though it slows down tracing too much to leave it enabled.
+#define ENABLE_RENDER_TREE_VISITOR_TRACING 0
+
+#if ENABLE_RENDER_TREE_VISITOR_TRACING
+#define TRACE_EVENT0_IF_ENABLED(x) TRACE_EVENT0("cobalt::renderer", x)
+#else
+#define TRACE_EVENT0_IF_ENABLED(x)
+#endif
+
namespace cobalt {
namespace renderer {
namespace rasterizer {
@@ -78,6 +90,8 @@
void RenderTreeNodeVisitor::Visit(
render_tree::CompositionNode* composition_node) {
+ TRACE_EVENT0_IF_ENABLED("Visit(CompositionNode)");
+
const render_tree::CompositionNode::Children& children =
composition_node->data().children();
@@ -119,6 +133,8 @@
} // namespace
void RenderTreeNodeVisitor::Visit(render_tree::FilterNode* filter_node) {
+ TRACE_EVENT0_IF_ENABLED("Visit(FilterNode)");
+
if (filter_node->data().blur_filter) {
// The Starboard Blitter API does not support blur filters, so we fallback
// to software for this.
@@ -193,6 +209,8 @@
}
void RenderTreeNodeVisitor::Visit(render_tree::ImageNode* image_node) {
+ TRACE_EVENT0_IF_ENABLED("Visit(ImageNode)");
+
// All Blitter API images derive from skia::Image (so that they can be
// compatible with the Skia software renderer), so we start here by casting
// to skia::Image.
@@ -252,6 +270,8 @@
void RenderTreeNodeVisitor::Visit(
render_tree::MatrixTransformNode* matrix_transform_node) {
+ TRACE_EVENT0_IF_ENABLED("Visit(MatrixTransformNode)");
+
const Matrix3F& transform = matrix_transform_node->data().transform;
if (transform.Get(1, 0) != 0 || transform.Get(0, 1) != 0 ||
@@ -276,20 +296,16 @@
void RenderTreeNodeVisitor::Visit(
render_tree::PunchThroughVideoNode* punch_through_video_node) {
+ TRACE_EVENT0_IF_ENABLED("Visit(PunchThroughVideoNode)");
+
SbBlitterRect blitter_rect =
RectFToBlitterRect(render_state_.transform.TransformRect(
punch_through_video_node->data().rect));
- if (punch_through_video_node->data().set_bounds_cb.is_null()) {
- return;
- }
- bool render_punch_through =
- punch_through_video_node->data().set_bounds_cb.Run(
- math::Rect(blitter_rect.x, blitter_rect.y, blitter_rect.width,
- blitter_rect.height));
- if (!render_punch_through) {
- return;
- }
+ punch_through_video_node->data().set_bounds_cb.Run(
+ math::Rect(blitter_rect.x, blitter_rect.y, blitter_rect.width,
+ blitter_rect.height));
+
SbBlitterSetColor(context_, SbBlitterColorFromRGBA(0, 0, 0, 0));
SbBlitterSetBlending(context_, false);
SbBlitterFillRect(context_, blitter_rect);
@@ -355,6 +371,8 @@
} // namespace
void RenderTreeNodeVisitor::Visit(render_tree::RectNode* rect_node) {
+ TRACE_EVENT0_IF_ENABLED("Visit(RectNode)");
+
if (rect_node->data().rounded_corners) {
// We can't render rounded corners through the Blitter API.
RenderWithSoftwareRenderer(rect_node);
@@ -436,15 +454,20 @@
void RenderTreeNodeVisitor::Visit(
render_tree::RectShadowNode* rect_shadow_node) {
+ TRACE_EVENT0_IF_ENABLED("Visit(RectShadowNode)");
+
RenderWithSoftwareRenderer(rect_shadow_node);
}
void RenderTreeNodeVisitor::Visit(render_tree::TextNode* text_node) {
+ TRACE_EVENT0_IF_ENABLED("Visit(TextNode)");
+
RenderWithSoftwareRenderer(text_node);
}
void RenderTreeNodeVisitor::RenderWithSoftwareRenderer(
render_tree::Node* node) {
+ TRACE_EVENT0("cobalt::renderer", "RenderWithSoftwareRenderer()");
CachedSoftwareRasterizer::SurfaceReference software_surface_reference(
software_surface_cache_, node, render_state_.transform);
CachedSoftwareRasterizer::Surface software_surface =
@@ -483,6 +506,7 @@
} else // NOLINT(readability/braces)
#endif // defined(ENABLE_DEBUG_CONSOLE)
{
+ TRACE_EVENT0("cobalt::renderer", "SbBlitterBlitRectToRect()");
SbBlitterBlitRectToRect(
context_, software_surface.surface,
SbBlitterMakeRect(
@@ -494,6 +518,8 @@
scoped_ptr<RenderTreeNodeVisitor::OffscreenRender>
RenderTreeNodeVisitor::RenderToOffscreenSurface(render_tree::Node* node) {
+ TRACE_EVENT0_IF_ENABLED("RenderToOffscreenSurface()");
+
common::OffscreenRenderCoordinateMapping coord_mapping =
common::GetOffscreenRenderCoordinateMapping(
node->GetBounds(), render_state_.transform.ToMatrix(),
diff --git a/src/cobalt/renderer/rasterizer/blitter/software_rasterizer.cc b/src/cobalt/renderer/rasterizer/blitter/software_rasterizer.cc
index 6622fbc..f96d931 100644
--- a/src/cobalt/renderer/rasterizer/blitter/software_rasterizer.cc
+++ b/src/cobalt/renderer/rasterizer/blitter/software_rasterizer.cc
@@ -95,7 +95,9 @@
SbBlitterDestroySurface(surface);
+ frame_rate_throttler_.EndInterval();
render_target_blitter->Flip();
+ frame_rate_throttler_.BeginInterval();
}
render_tree::ResourceProvider* SoftwareRasterizer::GetResourceProvider() {
diff --git a/src/cobalt/renderer/rasterizer/blitter/software_rasterizer.h b/src/cobalt/renderer/rasterizer/blitter/software_rasterizer.h
index 646f3c4..04aa2ac 100644
--- a/src/cobalt/renderer/rasterizer/blitter/software_rasterizer.h
+++ b/src/cobalt/renderer/rasterizer/blitter/software_rasterizer.h
@@ -26,6 +26,7 @@
#include "cobalt/renderer/backend/blitter/graphics_context.h"
#include "cobalt/renderer/backend/graphics_context.h"
#include "cobalt/renderer/backend/render_target.h"
+#include "cobalt/renderer/frame_rate_throttler.h"
#include "cobalt/renderer/rasterizer/rasterizer.h"
#include "cobalt/renderer/rasterizer/skia/software_rasterizer.h"
@@ -51,6 +52,7 @@
private:
backend::GraphicsContextBlitter* context_;
skia::SoftwareRasterizer skia_rasterizer_;
+ FrameRateThrottler frame_rate_throttler_;
};
} // namespace blitter
diff --git a/src/cobalt/renderer/rasterizer/egl/software_rasterizer.cc b/src/cobalt/renderer/rasterizer/egl/software_rasterizer.cc
index 97fcc63..8798b04 100644
--- a/src/cobalt/renderer/rasterizer/egl/software_rasterizer.cc
+++ b/src/cobalt/renderer/rasterizer/egl/software_rasterizer.cc
@@ -92,7 +92,9 @@
context_, render_target_egl);
context_->Blit(output_texture->gl_handle(), 0, 0, width, height);
+ frame_rate_throttler_.EndInterval();
context_->SwapBuffers(render_target_egl);
+ frame_rate_throttler_.BeginInterval();
}
render_tree::ResourceProvider* SoftwareRasterizer::GetResourceProvider() {
diff --git a/src/cobalt/renderer/rasterizer/egl/software_rasterizer.h b/src/cobalt/renderer/rasterizer/egl/software_rasterizer.h
index 8ae5e84..479ce7e 100644
--- a/src/cobalt/renderer/rasterizer/egl/software_rasterizer.h
+++ b/src/cobalt/renderer/rasterizer/egl/software_rasterizer.h
@@ -21,6 +21,7 @@
#include "cobalt/render_tree/resource_provider.h"
#include "cobalt/renderer/backend/graphics_context.h"
#include "cobalt/renderer/backend/render_target.h"
+#include "cobalt/renderer/frame_rate_throttler.h"
#include "cobalt/renderer/rasterizer/rasterizer.h"
#include "cobalt/renderer/rasterizer/skia/software_rasterizer.h"
@@ -51,6 +52,7 @@
private:
backend::GraphicsContextEGL* context_;
skia::SoftwareRasterizer skia_rasterizer_;
+ FrameRateThrottler frame_rate_throttler_;
};
} // namespace egl
diff --git a/src/cobalt/renderer/rasterizer/pixel_test.cc b/src/cobalt/renderer/rasterizer/pixel_test.cc
index 2fd11a4..68e4c7a 100644
--- a/src/cobalt/renderer/rasterizer/pixel_test.cc
+++ b/src/cobalt/renderer/rasterizer/pixel_test.cc
@@ -2802,8 +2802,8 @@
RoundedCorners(50, 50)));
}
-// If SetBoundsCB() returns false, the PunchThroughVideoNode should have no
-// effect.
+// PunchThroughVideoNode should trigger the painting of a solid rectangle with
+// RGBA(0, 0, 0, 0) regardless of whether SetBoundsCB returns true or false.
TEST_F(PixelTest, PunchThroughVideoNodePunchesThroughSetBoundsCBReturnsFalse) {
CompositionNode::Builder builder;
builder.AddChild(new RectNode(RectF(25, 25, 150, 150),
@@ -2816,8 +2816,6 @@
TestTree(new CompositionNode(builder.Pass()));
}
-// If SetBoundsCB() returns true, the PunchThroughVideoNode should trigger the
-// painting of a solid rectangle with RGBA(0, 0, 0, 0).
TEST_F(PixelTest, PunchThroughVideoNodePunchesThroughSetBoundsCBReturnsTrue) {
CompositionNode::Builder builder;
builder.AddChild(new RectNode(RectF(25, 25, 150, 150),
diff --git a/src/cobalt/renderer/rasterizer/skia/hardware_rasterizer.cc b/src/cobalt/renderer/rasterizer/skia/hardware_rasterizer.cc
index c3e2a0d..2ea8e6e 100644
--- a/src/cobalt/renderer/rasterizer/skia/hardware_rasterizer.cc
+++ b/src/cobalt/renderer/rasterizer/skia/hardware_rasterizer.cc
@@ -20,6 +20,8 @@
#include "base/debug/trace_event.h"
#include "cobalt/renderer/backend/egl/graphics_context.h"
+#include "cobalt/renderer/backend/egl/graphics_system.h"
+#include "cobalt/renderer/frame_rate_throttler.h"
#include "cobalt/renderer/rasterizer/common/surface_cache.h"
#include "cobalt/renderer/rasterizer/skia/cobalt_skia_type_conversions.h"
#include "cobalt/renderer/rasterizer/skia/hardware_resource_provider.h"
@@ -85,6 +87,8 @@
base::optional<SurfaceCacheDelegate> surface_cache_delegate_;
base::optional<common::SurfaceCache> surface_cache_;
+
+ FrameRateThrottler frame_rate_throttler_;
};
namespace {
@@ -231,6 +235,13 @@
if (options.flags & Rasterizer::kSubmitFlags_Clear) {
canvas->clear(SkColorSetARGB(0, 0, 0, 0));
+ } else if (options.dirty) {
+ // Only a portion of the display is dirty. Reuse the previous frame
+ // if possible.
+ if (render_target_egl->IsContentPreservedOnSwap() &&
+ render_target_egl->swap_count() >= 3) {
+ canvas->clipRect(CobaltRectFToSkiaRect(*options.dirty));
+ }
}
{
@@ -254,7 +265,9 @@
canvas->flush();
}
+ frame_rate_throttler_.EndInterval();
graphics_context_->SwapBuffers(render_target_egl);
+ frame_rate_throttler_.BeginInterval();
canvas->restore();
}
diff --git a/src/cobalt/renderer/rasterizer/skia/hardware_resource_provider.cc b/src/cobalt/renderer/rasterizer/skia/hardware_resource_provider.cc
index a17b893..195b6fb 100644
--- a/src/cobalt/renderer/rasterizer/skia/hardware_resource_provider.cc
+++ b/src/cobalt/renderer/rasterizer/skia/hardware_resource_provider.cc
@@ -177,14 +177,13 @@
SkFontMgr_Cobalt* font_manager =
base::polymorphic_downcast<SkFontMgr_Cobalt*>(font_manager_.get());
- SkTypeface* typeface = font_manager->matchFaceNameOnlyIfFound(font_face_name);
- SkiaTypeface* skia_type_face = NULL;
+ SkTypeface* typeface = font_manager->matchFaceName(font_face_name);
if (typeface != NULL) {
SkAutoTUnref<SkTypeface> typeface_unref_helper(typeface);
- skia_type_face = new SkiaTypeface(typeface);
+ return scoped_refptr<render_tree::Typeface>(new SkiaTypeface(typeface));
}
- return scoped_refptr<render_tree::Typeface>(skia_type_face);
+ return NULL;
}
scoped_refptr<render_tree::Typeface>
diff --git a/src/cobalt/renderer/rasterizer/skia/render_tree_node_visitor.cc b/src/cobalt/renderer/rasterizer/skia/render_tree_node_visitor.cc
index 9e2116d..fd5dfd9 100644
--- a/src/cobalt/renderer/rasterizer/skia/render_tree_node_visitor.cc
+++ b/src/cobalt/renderer/rasterizer/skia/render_tree_node_visitor.cc
@@ -737,18 +737,11 @@
SkRect sk_rect_transformed;
total_matrix.mapRect(&sk_rect_transformed, sk_rect);
- if (punch_through_video_node->data().set_bounds_cb.is_null()) {
- return;
- }
- bool render_punch_through =
- punch_through_video_node->data().set_bounds_cb.Run(
- math::Rect(static_cast<int>(sk_rect_transformed.x()),
- static_cast<int>(sk_rect_transformed.y()),
- static_cast<int>(sk_rect_transformed.width()),
- static_cast<int>(sk_rect_transformed.height())));
- if (!render_punch_through) {
- return;
- }
+ punch_through_video_node->data().set_bounds_cb.Run(
+ math::Rect(static_cast<int>(sk_rect_transformed.x()),
+ static_cast<int>(sk_rect_transformed.y()),
+ static_cast<int>(sk_rect_transformed.width()),
+ static_cast<int>(sk_rect_transformed.height())));
SkPaint paint;
paint.setXfermodeMode(SkXfermode::kSrc_Mode);
diff --git a/src/cobalt/renderer/rasterizer/skia/skia/src/ports/SkFontConfigParser_cobalt.cc b/src/cobalt/renderer/rasterizer/skia/skia/src/ports/SkFontConfigParser_cobalt.cc
index 63f1e67..4111f1b 100644
--- a/src/cobalt/renderer/rasterizer/skia/skia/src/ports/SkFontConfigParser_cobalt.cc
+++ b/src/cobalt/renderer/rasterizer/skia/skia/src/ports/SkFontConfigParser_cobalt.cc
@@ -300,7 +300,7 @@
break;
case 15:
if (strncmp("postscript_name", name, 15) == 0) {
- file->postcript_name = value;
+ file->postscript_name = value;
seen_attributes_flag |= kSeenFontPostscriptName;
continue;
}
@@ -341,7 +341,7 @@
DCHECK_EQ(seen_attributes_flag, kSeenFontFullName | kSeenFontPostscriptName |
kSeenWeight | kSeenStyle);
DCHECK(!file->full_font_name.isEmpty());
- DCHECK(!file->postcript_name.isEmpty());
+ DCHECK(!file->postscript_name.isEmpty());
}
FontFamily* FindFamily(FamilyData* family_data, const char* family_name) {
diff --git a/src/cobalt/renderer/rasterizer/skia/skia/src/ports/SkFontMgr_cobalt.cc b/src/cobalt/renderer/rasterizer/skia/skia/src/ports/SkFontMgr_cobalt.cc
index 5ab5536..6c9aa9d 100644
--- a/src/cobalt/renderer/rasterizer/skia/skia/src/ports/SkFontMgr_cobalt.cc
+++ b/src/cobalt/renderer/rasterizer/skia/skia/src/ports/SkFontMgr_cobalt.cc
@@ -25,6 +25,7 @@
#include "base/at_exit.h"
#include "base/bind.h"
+#include "base/debug/trace_event.h"
#include "base/lazy_instance.h"
#include "base/memory/singleton.h"
#include "cobalt/base/c_val.h"
@@ -48,6 +49,8 @@
// NOTE: It is the responsibility of the caller to call Unref() on the SkData.
SkData* NewDataFromFile(const SkString& file_path) {
+ TRACE_EVENT1("cobalt::renderer", "SkFontMgr_cobalt::NewDataFromFile()",
+ "file_path", TRACE_STR_COPY(file_path.c_str()));
LOG(INFO) << "Loading font file: " << file_path.c_str();
SkAutoTUnref<SkStream> file_stream(SkStream::NewFromFile(file_path.c_str()));
@@ -159,6 +162,7 @@
}
virtual SkStream* onOpenStream(int* ttc_index) const SK_OVERRIDE {
+ TRACE_EVENT0("cobalt::renderer", "SkTypeface_CobaltSystem::onOpenStream()");
*ttc_index = index_;
// Scope the initial mutex lock.
@@ -175,6 +179,7 @@
}
}
+ TRACE_EVENT0("cobalt::renderer", "Load data from file");
// This is where the bulk of the time will be spent, so load the font data
// outside of a mutex lock.
SkAutoTUnref<SkData> data(NewDataFromFile(path_name_));
@@ -237,6 +242,8 @@
language_(family.language),
page_ranges_(family.page_ranges),
is_character_map_generated_(false) {
+ TRACE_EVENT0("cobalt::renderer",
+ "SkFontStyleSet_Cobalt::SkFontStyleSet_Cobalt()");
DCHECK(manager_owned_mutex_);
if (family.names.count() == 0) {
@@ -269,12 +276,12 @@
std::string full_font_name(font_file.full_font_name.c_str(),
font_file.full_font_name.size());
- std::string postcript_name(font_file.postcript_name.c_str(),
- font_file.postcript_name.size());
+ std::string postscript_name(font_file.postscript_name.c_str(),
+ font_file.postscript_name.size());
styles_.push_back().reset(SkNEW_ARGS(
SkFontStyleSetEntry_Cobalt,
- (path_name, font_file.index, style, full_font_name, postcript_name)));
+ (path_name, font_file.index, style, full_font_name, postscript_name)));
}
}
@@ -306,34 +313,57 @@
SkTypeface* SkFontStyleSet_Cobalt::MatchStyleWithoutLocking(
const SkFontStyle& pattern) {
- while (styles_.count() > 0) {
- int style_index = GetClosestStyleIndex(pattern);
- SkFontStyleSetEntry_Cobalt* style = styles_[style_index];
- if (style->typeface == NULL) {
- CreateSystemTypeface(style);
-
- // Check to see if the typeface is still NULL. If this is the case, then
- // the style can't be created. Remove it from the array.
- if (style->typeface == NULL) {
- styles_[style_index].swap(&styles_.back());
- styles_.pop_back();
- continue;
- }
- }
-
- return SkRef(style->typeface.get());
+ SkTypeface* typeface = NULL;
+ while (typeface == NULL && styles_.count() > 0) {
+ typeface = TryRetrieveTypefaceAndRemoveStyleOnFailure(
+ GetClosestStyleIndex(pattern));
}
+ return typeface;
+}
+SkTypeface* SkFontStyleSet_Cobalt::MatchFullFontName(const std::string& name) {
+ for (int i = 0; i < styles_.count(); ++i) {
+ if (styles_[i]->full_font_name == name) {
+ return TryRetrieveTypefaceAndRemoveStyleOnFailure(i);
+ }
+ }
return NULL;
}
+SkTypeface* SkFontStyleSet_Cobalt::MatchFontPostScriptName(
+ const std::string& name) {
+ for (int i = 0; i < styles_.count(); ++i) {
+ if (styles_[i]->font_postscript_name == name) {
+ return TryRetrieveTypefaceAndRemoveStyleOnFailure(i);
+ }
+ }
+ return NULL;
+}
+
+SkTypeface* SkFontStyleSet_Cobalt::TryRetrieveTypefaceAndRemoveStyleOnFailure(
+ int style_index) {
+ DCHECK(style_index >= 0 && style_index < styles_.count());
+ SkFontStyleSetEntry_Cobalt* style = styles_[style_index];
+ // If the typeface doesn't already exist, then attempt to create it.
+ if (style->typeface == NULL) {
+ CreateSystemTypeface(style);
+ // If the creation attempt failed and the typeface is still NULL, then
+ // remove the entry from the set's styles.
+ if (style->typeface == NULL) {
+ styles_[style_index].swap(&styles_.back());
+ styles_.pop_back();
+ return NULL;
+ }
+ }
+ return SkRef(style->typeface.get());
+}
+
bool SkFontStyleSet_Cobalt::ContainsTypeface(const SkTypeface* typeface) {
for (int i = 0; i < styles_.count(); ++i) {
if (styles_[i]->typeface == typeface) {
return true;
}
}
-
return false;
}
@@ -371,6 +401,9 @@
// The character map is lazily generated. Generate it now if it isn't already
// generated.
if (!is_character_map_generated_) {
+ TRACE_EVENT0("cobalt::renderer",
+ "SkFontStyleSet_Cobalt::ContainsCharacter() and "
+ "!is_character_map_generated_");
// Attempt to load the closest font style from the set. If it fails to load,
// it will be removed from the set and, as long as font styles remain in the
// set, the logic will be attempted again.
@@ -422,6 +455,7 @@
if (is_character_map_generated_) {
return;
}
+ TRACE_EVENT0("cobalt::renderer", "GenerateCharacterMapFromData()");
FT_Library freetype_lib;
if (FT_Init_FreeType(&freetype_lib) != 0) {
@@ -476,6 +510,8 @@
void SkFontStyleSet_Cobalt::CreateSystemTypeface(
SkFontStyleSetEntry_Cobalt* style_entry) {
+ TRACE_EVENT0("cobalt::renderer",
+ "SkFontStyleSet_Cobalt::CreateSystemTypeface()");
SkAutoTUnref<SkData> font_data(NewDataFromFile(style_entry->font_file_path));
if (font_data != NULL) {
CreateSystemTypefaceFromData(style_entry, font_data);
@@ -484,6 +520,8 @@
void SkFontStyleSet_Cobalt::CreateSystemTypefaceFromData(
SkFontStyleSetEntry_Cobalt* style_entry, SkData* data) {
+ TRACE_EVENT0("cobalt::renderer",
+ "SkFontStyleSet_Cobalt::CreateSystemTypefaceFromData()");
DCHECK(!style_entry->typeface);
// Since the font data is available, generate the character map if this is a
@@ -582,13 +620,17 @@
const char* directory, const SkTArray<SkString, true>& default_fonts)
: default_family_(NULL),
last_font_cache_purge_time_(base::TimeTicks::Now()) {
+ TRACE_EVENT0("cobalt::renderer", "SkFontMgr_Cobalt::SkFontMgr_Cobalt()");
// Ensure that both the CValManager and SkFontMgrCVals are initialized. The
// CValManager is created first as it must outlast the SkFontMgrCVals.
base::CValManager::GetInstance();
SkFontMgrCVals::GetInstance();
SkTDArray<FontFamily*> font_families;
- SkFontConfigParser::GetFontFamilies(directory, &font_families);
+ {
+ TRACE_EVENT0("cobalt::renderer", "SkFontConfigParser::GetFontFamilies()");
+ SkFontConfigParser::GetFontFamilies(directory, &font_families);
+ }
BuildNameToFamilyMap(directory, &font_families);
font_families.deleteAll();
@@ -610,6 +652,41 @@
}
}
+SkTypeface* SkFontMgr_Cobalt::matchFaceName(const std::string& font_face_name) {
+ if (font_face_name.empty()) {
+ return NULL;
+ }
+
+ // Lock the style sets mutex prior to accessing them.
+ SkAutoMutexAcquire scoped_mutex(style_sets_mutex_);
+
+ // Prioritize looking up the postscript name first since some of our client
+ // applications prefer this method to specify face names.
+ for (int i = 0; i <= 1; ++i) {
+ NameToStyleSetMap& name_to_style_set_map =
+ i == 0 ? font_postscript_name_to_style_set_map_
+ : full_font_name_to_style_set_map_;
+
+ NameToStyleSetMap::iterator style_set_iterator =
+ name_to_style_set_map.find(font_face_name);
+ if (style_set_iterator != name_to_style_set_map.end()) {
+ SkFontStyleSet_Cobalt* style_set = style_set_iterator->second;
+ SkTypeface* typeface =
+ i == 0 ? style_set->MatchFontPostScriptName(font_face_name)
+ : style_set->MatchFullFontName(font_face_name);
+ if (typeface != NULL) {
+ return typeface;
+ } else {
+ // If no typeface was successfully created then remove the entry from
+ // the map. It won't provide a successful result in subsequent calls
+ // either.
+ name_to_style_set_map.erase(style_set_iterator);
+ }
+ }
+ }
+ return NULL;
+}
+
int SkFontMgr_Cobalt::onCountFamilies() const { return family_names_.count(); }
void SkFontMgr_Cobalt::onGetFamilyName(int index, SkString* family_name) const {
@@ -626,7 +703,7 @@
return NULL;
}
- NameToFamilyMap::const_iterator family_iterator =
+ NameToStyleSetMap::const_iterator family_iterator =
name_to_family_map_.find(family_names_[index].c_str());
if (family_iterator != name_to_family_map_.end()) {
return SkRef(family_iterator->second);
@@ -643,7 +720,7 @@
SkAutoAsciiToLC tolc(family_name);
- NameToFamilyMap::const_iterator family_iterator =
+ NameToStyleSetMap::const_iterator family_iterator =
name_to_family_map_.find(tolc.lc());
if (family_iterator != name_to_family_map_.end()) {
return SkRef(family_iterator->second);
@@ -652,79 +729,6 @@
return NULL;
}
-SkTypeface* SkFontMgr_Cobalt::matchFullFontFaceNameHelper(
- SkFontStyleSet_Cobalt* style_set,
- SkFontStyleSet_Cobalt::SkFontStyleSetEntry_Cobalt* style) const {
- DCHECK(style_set != NULL);
- if (!style) {
- NOTREACHED() << "style should not be NULL.";
- return NULL;
- }
-
- if (style->typeface == NULL) {
- if (!style_set) {
- return NULL;
- }
- style_set->CreateSystemTypeface(style);
- }
-
- if (style->typeface != NULL) {
- return SkRef(style->typeface.get());
- }
-
- return NULL;
-}
-
-SkTypeface* SkFontMgr_Cobalt::matchFaceNameOnlyIfFound(
- const std::string& font_face_name) const {
- // Prioritize looking it up postscript name first since some of our client
- // applications prefer this method to specify face names.
- SkTypeface* typeface = matchPostScriptName(font_face_name);
- if (typeface != NULL) return typeface;
-
- typeface = matchFullFontFaceName(font_face_name);
- if (typeface != NULL) return typeface;
-
- return NULL;
-}
-
-SkTypeface* SkFontMgr_Cobalt::matchFullFontFaceName(
- const std::string& font_face_name) const {
- SkAutoMutexAcquire scoped_mutex(style_sets_mutex_);
-
- if (font_face_name.empty()) {
- return NULL;
- }
-
- FullFontNameToFontFaceInfoMap::const_iterator font_face_iterator =
- fullfontname_to_fontface_info_map_.find(font_face_name);
-
- if (font_face_iterator != fullfontname_to_fontface_info_map_.end()) {
- return matchFullFontFaceNameHelper(
- font_face_iterator->second.style_set_entry_parent,
- font_face_iterator->second.style_set_entry);
- }
-
- return NULL;
-}
-
-SkTypeface* SkFontMgr_Cobalt::matchPostScriptName(
- const std::string& font_face_name) const {
- if (font_face_name.empty()) {
- return NULL;
- }
-
- PostScriptToFontFaceInfoMap::const_iterator font_face_iterator =
- postscriptname_to_fontface_info_map_.find(font_face_name);
- if (font_face_iterator != postscriptname_to_fontface_info_map_.end()) {
- return matchFullFontFaceNameHelper(
- font_face_iterator->second.style_set_entry_parent,
- font_face_iterator->second.style_set_entry);
- }
-
- return NULL;
-}
-
SkTypeface* SkFontMgr_Cobalt::onMatchFamilyStyle(
const char family_name[], const SkFontStyle& style) const {
SkTypeface* tf = NULL;
@@ -807,6 +811,7 @@
SkTypeface* SkFontMgr_Cobalt::onCreateFromStream(SkStream* stream,
int ttc_index) const {
+ TRACE_EVENT0("cobalt::renderer", "SkFontMgr_Cobalt::onCreateFromStream()");
bool is_fixed_pitch;
SkTypeface::Style style;
SkString name;
@@ -820,6 +825,7 @@
SkTypeface* SkFontMgr_Cobalt::onCreateFromFile(const char path[],
int ttc_index) const {
+ TRACE_EVENT0("cobalt::renderer", "SkFontMgr_Cobalt::onCreateFromFile()");
SkAutoTUnref<SkStream> stream(SkStream::NewFromFile(path));
return stream.get() ? createFromStream(stream, ttc_index) : NULL;
}
@@ -838,6 +844,7 @@
void SkFontMgr_Cobalt::BuildNameToFamilyMap(const char* base_path,
SkTDArray<FontFamily*>* families) {
+ TRACE_EVENT0("cobalt::renderer", "SkFontMgr_Cobalt::BuildNameToFamilyMap()");
for (int i = 0; i < families->count(); i++) {
FontFamily& family = *(*families)[i];
bool named_font = family.names.count() > 0;
@@ -861,47 +868,32 @@
font_style_set_entry = new_set->styles_.begin();
font_style_set_entry != new_set->styles_.end();
++font_style_set_entry) {
- if (!font_style_set_entry) {
- NOTREACHED() << " Font Style entry is invalid";
- continue;
- } else if ((*font_style_set_entry).get() == NULL) {
- NOTREACHED() << " Font Style entry is NULL";
- continue;
- }
+ // On the first pass through, process the full font name.
+ // On the second pass through, process the font postscript name.
+ for (int i = 0; i <= 1; ++i) {
+ const std::string font_face_name_type_description =
+ i == 0 ? "Full Font" : "Postscript";
+ const std::string& font_face_name =
+ i == 0 ? (*font_style_set_entry)->full_font_name
+ : (*font_style_set_entry)->font_postscript_name;
+ NameToStyleSetMap& font_face_name_style_set_map =
+ i == 0 ? full_font_name_to_style_set_map_
+ : font_postscript_name_to_style_set_map_;
- const std::string& full_font_name =
- (*font_style_set_entry)->full_font_name;
- DCHECK(!full_font_name.empty());
- if (fullfontname_to_fontface_info_map_.find(full_font_name) ==
- fullfontname_to_fontface_info_map_.end()) {
- DLOG(INFO) << "Adding Full font name [" << full_font_name << "].";
- fullfontname_to_fontface_info_map_[full_font_name] =
- FullFontNameToFontFaceInfoMap::mapped_type(
- font_style_set_entry->get(), new_set.get());
- } else {
- // Purposely, not overwriting the entry gives priority to the
- // earlier entry. This is consistent with how fonts.xml gives
- // priority to fonts that are specified earlier in the file.
- NOTREACHED() << "Full font name [" << full_font_name
- << "] already registered in BuildNameToFamilyMap.";
- }
-
- const std::string& postscript_font_name =
- (*font_style_set_entry)->font_postscript_name;
- DCHECK(!postscript_font_name.empty());
- if (postscriptname_to_fontface_info_map_.find(postscript_font_name) ==
- postscriptname_to_fontface_info_map_.end()) {
- DLOG(INFO) << "Adding Postscript name [" << postscript_font_name
- << "].";
- postscriptname_to_fontface_info_map_[postscript_font_name] =
- PostScriptToFontFaceInfoMap::mapped_type(
- font_style_set_entry->get(), new_set.get());
- } else {
- // Purposely, not overwriting the entry gives priority to the
- // earlier entry. This is consistent with how fonts.xml gives
- // priority to fonts that are specified earlier in the file.
- NOTREACHED() << "Adding Postscript name [" << postscript_font_name
- << "] already registered in BuildNameToFamilyMap.";
+ DCHECK(!font_face_name.empty());
+ if (font_face_name_style_set_map.find(font_face_name) ==
+ font_face_name_style_set_map.end()) {
+ DLOG(INFO) << "Adding " << font_face_name_type_description
+ << " name [" << font_face_name << "].";
+ font_face_name_style_set_map[font_face_name] = new_set.get();
+ } else {
+ // Purposely, not overwriting the entry gives priority to the
+ // earlier entry. This is consistent with how fonts.xml gives
+ // priority to fonts that are specified earlier in the file.
+ NOTREACHED() << font_face_name_type_description << " name ["
+ << font_face_name
+ << "] already registered in BuildNameToFamilyMap.";
+ }
}
}
@@ -988,6 +980,29 @@
return NULL;
}
+void SkFontMgr_Cobalt::HandlePeriodicProcessing() {
+ base::TimeTicks current_time = base::TimeTicks::Now();
+
+ ProcessSystemTypefacesWithOpenStreams(current_time);
+
+ // If the required delay has elapsed since the last font cache purge, then
+ // it's time to force another. This is accomplished by setting the limit to
+ // 1 byte smaller than it's current size, which initiates a partial purge (it
+ // always purges at least 25% of its contents). After this is done, the cache
+ // is set back to its previous size.
+ if ((current_time - last_font_cache_purge_time_).InMilliseconds() >=
+ kPeriodicFontCachePurgeDelayMs) {
+ last_font_cache_purge_time_ = current_time;
+
+ size_t font_cache_used = SkGraphics::GetFontCacheUsed();
+ if (font_cache_used > 0) {
+ size_t font_cache_limit = SkGraphics::GetFontCacheLimit();
+ SkGraphics::SetFontCacheLimit(font_cache_used - 1);
+ SkGraphics::SetFontCacheLimit(font_cache_limit);
+ }
+ }
+}
+
// NOTE: It is the responsibility of the caller to lock
// |system_typeface_stream_mutex_|
void SkFontMgr_Cobalt::AddSystemTypefaceWithActiveOpenStream(
@@ -1024,26 +1039,6 @@
}
}
-void SkFontMgr_Cobalt::HandlePeriodicProcessing() {
- base::TimeTicks current_time = base::TimeTicks::Now();
-
- ProcessSystemTypefacesWithOpenStreams(current_time);
-
- // If the required delay has elapsed since the last font cache purge, then
- // it's time to force another. This is accomplished by setting the limit to
- // 1 byte smaller than it's current size, which initiates a partial purge (it
- // always purges at least 25% of its contents). After this is done, the cache
- // is set back to its previous size.
- if ((current_time - last_font_cache_purge_time_).InMilliseconds() >=
- kPeriodicFontCachePurgeDelayMs) {
- last_font_cache_purge_time_ = current_time;
-
- size_t font_cache_limit = SkGraphics::GetFontCacheLimit();
- SkGraphics::SetFontCacheLimit(SkGraphics::GetFontCacheUsed() - 1);
- SkGraphics::SetFontCacheLimit(font_cache_limit);
- }
-}
-
void SkFontMgr_Cobalt::ProcessSystemTypefacesWithOpenStreams(
const base::TimeTicks& current_time) const {
SkAutoMutexAcquire scoped_mutex(system_typeface_stream_mutex_);
diff --git a/src/cobalt/renderer/rasterizer/skia/skia/src/ports/SkFontMgr_cobalt.h b/src/cobalt/renderer/rasterizer/skia/skia/src/ports/SkFontMgr_cobalt.h
index cebba88..cc74881 100644
--- a/src/cobalt/renderer/rasterizer/skia/skia/src/ports/SkFontMgr_cobalt.h
+++ b/src/cobalt/renderer/rasterizer/skia/skia/src/ports/SkFontMgr_cobalt.h
@@ -46,6 +46,11 @@
class SkFontStyleSet_Cobalt : public SkFontStyleSet {
public:
struct SkFontStyleSetEntry_Cobalt : public SkRefCnt {
+ // NOTE: |SkFontStyleSetEntry_Cobalt| objects are not guaranteed to last for
+ // the lifetime of |SkFontMgr_Cobalt| and can be removed by their owning
+ // |SkFontStyleSet_Cobalt| if their typeface fails to load properly. As a
+ // result, it is not safe to store their pointers outside of
+ // |SkFontStyleSet_Cobalt|.
SkFontStyleSetEntry_Cobalt(const SkString& file_path, const int index,
const SkFontStyle& style,
const std::string& full_name,
@@ -92,6 +97,9 @@
// calling any of the non-const private functions.
SkTypeface* MatchStyleWithoutLocking(const SkFontStyle& pattern);
+ SkTypeface* MatchFullFontName(const std::string& name);
+ SkTypeface* MatchFontPostScriptName(const std::string& name);
+ SkTypeface* TryRetrieveTypefaceAndRemoveStyleOnFailure(int style_index);
bool ContainsTypeface(const SkTypeface* typeface);
bool ContainsCharacter(const SkFontStyle& style, SkUnichar character);
@@ -138,33 +146,30 @@
SkFontMgr_Cobalt(const char* directory,
const SkTArray<SkString, true>& default_fonts);
- // Note: Unlike the other similar onMatch* functions, this function can return
- // NULL. This is so that we can try other things in case the match is not
- // found.
- SkTypeface* matchFaceNameOnlyIfFound(const std::string& font_face_name) const;
+ // NOTE: This returns NULL if a match is not found.
+ SkTypeface* matchFaceName(const std::string& font_face_name);
protected:
- // Note: These match*Name helper functions can return NULL.
- SkTypeface* matchFullFontFaceName(const std::string& font_face_name) const;
- SkTypeface* matchPostScriptName(const std::string& font_face_name) const;
- SkTypeface* matchFullFontFaceNameHelper(
- SkFontStyleSet_Cobalt* style_set,
- SkFontStyleSet_Cobalt::SkFontStyleSetEntry_Cobalt* style) const;
-
// From SkFontMgr
virtual int onCountFamilies() const SK_OVERRIDE;
virtual void onGetFamilyName(int index,
SkString* family_name) const SK_OVERRIDE;
+ // NOTE: This returns NULL if there is no accessible style set at the index.
virtual SkFontStyleSet_Cobalt* onCreateStyleSet(int index) const SK_OVERRIDE;
+ // NOTE: This returns NULL if there is no family match.
virtual SkFontStyleSet_Cobalt* onMatchFamily(const char family_name[]) const
SK_OVERRIDE;
+ // NOTE: This always returns a non-NULL value. If the family name cannot be
+ // found, then the best match among the default family is returned.
virtual SkTypeface* onMatchFamilyStyle(
const char family_name[], const SkFontStyle& style) const SK_OVERRIDE;
+// NOTE: This always returns a non-NULL value. If no match can be found, then
+// the best match among the default family is returned.
#ifdef SK_FM_NEW_MATCH_FAMILY_STYLE_CHARACTER
virtual SkTypeface* onMatchFamilyStyleCharacter(
const char family_name[], const SkFontStyle& style, const char* bcp47[],
@@ -175,19 +180,25 @@
SkUnichar character) const SK_OVERRIDE;
#endif
+ // NOTE: This returns NULL if a match is not found.
virtual SkTypeface* onMatchFaceStyle(const SkTypeface* family_member,
const SkFontStyle& font_style) const
SK_OVERRIDE;
+ // NOTE: This returns NULL if the typeface cannot be created.
virtual SkTypeface* onCreateFromData(SkData* data,
int ttc_index) const SK_OVERRIDE;
+ // NOTE: This returns NULL if the typeface cannot be created.
virtual SkTypeface* onCreateFromStream(SkStream* stream,
int ttc_index) const SK_OVERRIDE;
+ // NOTE: This returns NULL if the typeface cannot be created.
virtual SkTypeface* onCreateFromFile(const char path[],
int ttc_index) const SK_OVERRIDE;
+ // NOTE: This always returns a non-NULL value. If no match can be found, then
+ // the best match among the default family is returned.
virtual SkTypeface* onLegacyCreateTypeface(
const char family_name[], unsigned style_bits) const SK_OVERRIDE;
@@ -201,23 +212,7 @@
base::TimeTicks time;
};
- // Map names to the back end so that all names for a given family refer to
- // the same (non-replicated) set of typefaces.
- typedef base::hash_map<std::string, SkFontStyleSet_Cobalt*> NameToFamilyMap;
-
- struct FontFaceInfo {
- FontFaceInfo() : style_set_entry(NULL), style_set_entry_parent(NULL) {}
- FontFaceInfo(SkFontStyleSet_Cobalt::SkFontStyleSetEntry_Cobalt* entry,
- SkFontStyleSet_Cobalt* parent)
- : style_set_entry(entry), style_set_entry_parent(parent) {}
-
- SkFontStyleSet_Cobalt::SkFontStyleSetEntry_Cobalt* style_set_entry;
- SkFontStyleSet_Cobalt* style_set_entry_parent;
- };
-
- typedef base::hash_map<std::string, FontFaceInfo>
- FullFontNameToFontFaceInfoMap;
- typedef base::hash_map<std::string, FontFaceInfo> PostScriptToFontFaceInfoMap;
+ typedef base::hash_map<std::string, SkFontStyleSet_Cobalt*> NameToStyleSetMap;
void BuildNameToFamilyMap(const char* base_path,
SkTDArray<FontFamily*>* families);
@@ -257,9 +252,11 @@
SkTArray<SkAutoTUnref<SkFontStyleSet_Cobalt>, true> font_style_sets_;
SkTArray<SkString> family_names_;
- NameToFamilyMap name_to_family_map_;
- FullFontNameToFontFaceInfoMap fullfontname_to_fontface_info_map_;
- PostScriptToFontFaceInfoMap postscriptname_to_fontface_info_map_;
+ // Map names to the back end so that all names for a given family refer to
+ // the same (non-replicated) set of typefaces.
+ NameToStyleSetMap name_to_family_map_;
+ NameToStyleSetMap full_font_name_to_style_set_map_;
+ NameToStyleSetMap font_postscript_name_to_style_set_map_;
SkTArray<SkFontStyleSet_Cobalt*> fallback_families_;
diff --git a/src/cobalt/renderer/rasterizer/skia/skia/src/ports/SkFontUtil_cobalt.h b/src/cobalt/renderer/rasterizer/skia/skia/src/ports/SkFontUtil_cobalt.h
index 020517c..80287a4 100644
--- a/src/cobalt/renderer/rasterizer/skia/skia/src/ports/SkFontUtil_cobalt.h
+++ b/src/cobalt/renderer/rasterizer/skia/skia/src/ports/SkFontUtil_cobalt.h
@@ -111,7 +111,7 @@
FontStyle style;
SkString full_font_name;
- SkString postcript_name;
+ SkString postscript_name;
};
// A font family provides one or more names for a collection of fonts, each of
diff --git a/src/cobalt/renderer/rasterizer/skia/software_resource_provider.cc b/src/cobalt/renderer/rasterizer/skia/software_resource_provider.cc
index d3af607..5a9afb7 100644
--- a/src/cobalt/renderer/rasterizer/skia/software_resource_provider.cc
+++ b/src/cobalt/renderer/rasterizer/skia/software_resource_provider.cc
@@ -127,7 +127,7 @@
SkFontMgr_Cobalt* font_manager =
base::polymorphic_downcast<SkFontMgr_Cobalt*>(font_manager_.get());
- SkTypeface* typeface = font_manager->matchFaceNameOnlyIfFound(font_face_name);
+ SkTypeface* typeface = font_manager->matchFaceName(font_face_name);
if (typeface != NULL) {
SkAutoTUnref<SkTypeface> typeface_unref_helper(typeface);
return scoped_refptr<render_tree::Typeface>(new SkiaTypeface(typeface));
diff --git a/src/cobalt/renderer/rasterizer/testdata/PunchThroughVideoNodePunchesThroughSetBoundsCBReturnsFalse-expected.png b/src/cobalt/renderer/rasterizer/testdata/PunchThroughVideoNodePunchesThroughSetBoundsCBReturnsFalse-expected.png
index d26f087..0f82d7a 100644
--- a/src/cobalt/renderer/rasterizer/testdata/PunchThroughVideoNodePunchesThroughSetBoundsCBReturnsFalse-expected.png
+++ b/src/cobalt/renderer/rasterizer/testdata/PunchThroughVideoNodePunchesThroughSetBoundsCBReturnsFalse-expected.png
Binary files differ
diff --git a/src/cobalt/renderer/renderer.gyp b/src/cobalt/renderer/renderer.gyp
index 5a1253e..d7619d5 100644
--- a/src/cobalt/renderer/renderer.gyp
+++ b/src/cobalt/renderer/renderer.gyp
@@ -22,6 +22,8 @@
'target_name': 'renderer',
'type': 'static_library',
'sources': [
+ 'frame_rate_throttler.cc',
+ 'frame_rate_throttler.h',
'pipeline.cc',
'pipeline.h',
'renderer_module.cc',
@@ -33,6 +35,9 @@
'submission_queue.h',
],
+ 'defines': [
+ 'COBALT_MINIMUM_FRAME_TIME_IN_MILLISECONDS=<(cobalt_minimum_frame_time_in_milliseconds)',
+ ],
'includes': [
'copy_font_data.gypi',
],
diff --git a/src/cobalt/renderer/renderer_module_default_options_starboard.cc b/src/cobalt/renderer/renderer_module_default_options_starboard.cc
index 7ee0e3e..c19cc0b 100644
--- a/src/cobalt/renderer/renderer_module_default_options_starboard.cc
+++ b/src/cobalt/renderer/renderer_module_default_options_starboard.cc
@@ -16,6 +16,7 @@
#include "cobalt/renderer/renderer_module.h"
+#include "base/debug/trace_event.h"
#include "cobalt/renderer/rasterizer/blitter/hardware_rasterizer.h"
#include "cobalt/renderer/rasterizer/blitter/software_rasterizer.h"
#include "cobalt/renderer/rasterizer/egl/software_rasterizer.h"
@@ -30,6 +31,7 @@
scoped_ptr<rasterizer::Rasterizer> CreateRasterizer(
backend::GraphicsContext* graphics_context,
const RendererModule::Options& options) {
+ TRACE_EVENT0("cobalt::renderer", "CreateRasterizer");
#if COBALT_FORCE_STUB_RASTERIZER
return scoped_ptr<rasterizer::Rasterizer>(new rasterizer::stub::Rasterizer());
#else
diff --git a/src/cobalt/script/mozjs/mozjs_callback_function.h b/src/cobalt/script/mozjs/mozjs_callback_function.h
index 71d8914..ef6932a 100644
--- a/src/cobalt/script/mozjs/mozjs_callback_function.h
+++ b/src/cobalt/script/mozjs/mozjs_callback_function.h
@@ -27,7 +27,9 @@
#include "cobalt/script/callback_function.h"
#include "cobalt/script/mozjs/conversion_helpers.h"
#include "cobalt/script/mozjs/convert_callback_return_value.h"
+#include "cobalt/script/mozjs/util/exception_helpers.h"
#include "cobalt/script/mozjs/weak_heap_object.h"
+#include "nb/memory_scope.h"
#include "third_party/mozjs/js/src/jsapi.h"
#include "third_party/mozjs/js/src/jscntxt.h"
@@ -57,6 +59,7 @@
CallbackResult<R> Run()
const OVERRIDE {
+ TRACK_MEMORY_SCOPE("Javascript");
TRACE_EVENT0("cobalt::script::mozjs", "MozjsCallbackFunction::Run");
CallbackResult<R> callback_result;
JSAutoRequest auto_request(context_);
@@ -79,7 +82,8 @@
JSBool call_result = JS::Call(context_, this_value, function, 0, NULL,
return_value.address());
if (!call_result) {
- DLOG(WARNING) << "Exception in callback.";
+ DLOG(WARNING) << "Exception in callback: "
+ << util::GetExceptionString(context_);
callback_result.exception = true;
} else {
callback_result = ConvertCallbackReturnValue<R>(context_, return_value);
@@ -111,6 +115,7 @@
CallbackResult<R> Run(
typename base::internal::CallbackParamTraits<A1>::ForwardType a1)
const OVERRIDE {
+ TRACK_MEMORY_SCOPE("Javascript");
TRACE_EVENT0("cobalt::script::mozjs", "MozjsCallbackFunction::Run");
CallbackResult<R> callback_result;
JSAutoRequest auto_request(context_);
@@ -138,7 +143,8 @@
JSBool call_result = JS::Call(context_, this_value, function,
kNumArguments, args, return_value.address());
if (!call_result) {
- DLOG(WARNING) << "Exception in callback.";
+ DLOG(WARNING) << "Exception in callback: "
+ << util::GetExceptionString(context_);
callback_result.exception = true;
} else {
callback_result = ConvertCallbackReturnValue<R>(context_, return_value);
@@ -171,6 +177,7 @@
typename base::internal::CallbackParamTraits<A1>::ForwardType a1,
typename base::internal::CallbackParamTraits<A2>::ForwardType a2)
const OVERRIDE {
+ TRACK_MEMORY_SCOPE("Javascript");
TRACE_EVENT0("cobalt::script::mozjs", "MozjsCallbackFunction::Run");
CallbackResult<R> callback_result;
JSAutoRequest auto_request(context_);
@@ -199,7 +206,8 @@
JSBool call_result = JS::Call(context_, this_value, function,
kNumArguments, args, return_value.address());
if (!call_result) {
- DLOG(WARNING) << "Exception in callback.";
+ DLOG(WARNING) << "Exception in callback: "
+ << util::GetExceptionString(context_);
callback_result.exception = true;
} else {
callback_result = ConvertCallbackReturnValue<R>(context_, return_value);
@@ -233,6 +241,7 @@
typename base::internal::CallbackParamTraits<A2>::ForwardType a2,
typename base::internal::CallbackParamTraits<A3>::ForwardType a3)
const OVERRIDE {
+ TRACK_MEMORY_SCOPE("Javascript");
TRACE_EVENT0("cobalt::script::mozjs", "MozjsCallbackFunction::Run");
CallbackResult<R> callback_result;
JSAutoRequest auto_request(context_);
@@ -262,7 +271,8 @@
JSBool call_result = JS::Call(context_, this_value, function,
kNumArguments, args, return_value.address());
if (!call_result) {
- DLOG(WARNING) << "Exception in callback.";
+ DLOG(WARNING) << "Exception in callback: "
+ << util::GetExceptionString(context_);
callback_result.exception = true;
} else {
callback_result = ConvertCallbackReturnValue<R>(context_, return_value);
@@ -297,6 +307,7 @@
typename base::internal::CallbackParamTraits<A3>::ForwardType a3,
typename base::internal::CallbackParamTraits<A4>::ForwardType a4)
const OVERRIDE {
+ TRACK_MEMORY_SCOPE("Javascript");
TRACE_EVENT0("cobalt::script::mozjs", "MozjsCallbackFunction::Run");
CallbackResult<R> callback_result;
JSAutoRequest auto_request(context_);
@@ -327,7 +338,8 @@
JSBool call_result = JS::Call(context_, this_value, function,
kNumArguments, args, return_value.address());
if (!call_result) {
- DLOG(WARNING) << "Exception in callback.";
+ DLOG(WARNING) << "Exception in callback: "
+ << util::GetExceptionString(context_);
callback_result.exception = true;
} else {
callback_result = ConvertCallbackReturnValue<R>(context_, return_value);
@@ -364,6 +376,7 @@
typename base::internal::CallbackParamTraits<A4>::ForwardType a4,
typename base::internal::CallbackParamTraits<A5>::ForwardType a5)
const OVERRIDE {
+ TRACK_MEMORY_SCOPE("Javascript");
TRACE_EVENT0("cobalt::script::mozjs", "MozjsCallbackFunction::Run");
CallbackResult<R> callback_result;
JSAutoRequest auto_request(context_);
@@ -395,7 +408,8 @@
JSBool call_result = JS::Call(context_, this_value, function,
kNumArguments, args, return_value.address());
if (!call_result) {
- DLOG(WARNING) << "Exception in callback.";
+ DLOG(WARNING) << "Exception in callback: "
+ << util::GetExceptionString(context_);
callback_result.exception = true;
} else {
callback_result = ConvertCallbackReturnValue<R>(context_, return_value);
@@ -433,6 +447,7 @@
typename base::internal::CallbackParamTraits<A5>::ForwardType a5,
typename base::internal::CallbackParamTraits<A6>::ForwardType a6)
const OVERRIDE {
+ TRACK_MEMORY_SCOPE("Javascript");
TRACE_EVENT0("cobalt::script::mozjs", "MozjsCallbackFunction::Run");
CallbackResult<R> callback_result;
JSAutoRequest auto_request(context_);
@@ -465,7 +480,8 @@
JSBool call_result = JS::Call(context_, this_value, function,
kNumArguments, args, return_value.address());
if (!call_result) {
- DLOG(WARNING) << "Exception in callback.";
+ DLOG(WARNING) << "Exception in callback: "
+ << util::GetExceptionString(context_);
callback_result.exception = true;
} else {
callback_result = ConvertCallbackReturnValue<R>(context_, return_value);
@@ -504,6 +520,7 @@
typename base::internal::CallbackParamTraits<A6>::ForwardType a6,
typename base::internal::CallbackParamTraits<A7>::ForwardType a7)
const OVERRIDE {
+ TRACK_MEMORY_SCOPE("Javascript");
TRACE_EVENT0("cobalt::script::mozjs", "MozjsCallbackFunction::Run");
CallbackResult<R> callback_result;
JSAutoRequest auto_request(context_);
@@ -537,7 +554,8 @@
JSBool call_result = JS::Call(context_, this_value, function,
kNumArguments, args, return_value.address());
if (!call_result) {
- DLOG(WARNING) << "Exception in callback.";
+ DLOG(WARNING) << "Exception in callback: "
+ << util::GetExceptionString(context_);
callback_result.exception = true;
} else {
callback_result = ConvertCallbackReturnValue<R>(context_, return_value);
diff --git a/src/cobalt/script/mozjs/mozjs_callback_function.h.pump b/src/cobalt/script/mozjs/mozjs_callback_function.h.pump
index 861dcd3..9bfb5f2 100644
--- a/src/cobalt/script/mozjs/mozjs_callback_function.h.pump
+++ b/src/cobalt/script/mozjs/mozjs_callback_function.h.pump
@@ -32,7 +32,9 @@
#include "cobalt/script/callback_function.h"
#include "cobalt/script/mozjs/conversion_helpers.h"
#include "cobalt/script/mozjs/convert_callback_return_value.h"
+#include "cobalt/script/mozjs/util/exception_helpers.h"
#include "cobalt/script/mozjs/weak_heap_object.h"
+#include "nb/memory_scope.h"
#include "third_party/mozjs/js/src/jsapi.h"
#include "third_party/mozjs/js/src/jscntxt.h"
@@ -76,6 +78,7 @@
typename base::internal::CallbackParamTraits<A$(ARG)>::ForwardType a$(ARG)]])
const OVERRIDE {
+ TRACK_MEMORY_SCOPE("Javascript");
TRACE_EVENT0("cobalt::script::mozjs", "MozjsCallbackFunction::Run");
CallbackResult<R> callback_result;
JSAutoRequest auto_request(context_);
@@ -110,7 +113,8 @@
]]
if (!call_result) {
- DLOG(WARNING) << "Exception in callback.";
+ DLOG(WARNING) << "Exception in callback: "
+ << util::GetExceptionString(context_);
callback_result.exception = true;
} else {
callback_result = ConvertCallbackReturnValue<R>(context_, return_value);
diff --git a/src/cobalt/script/mozjs/mozjs_engine.cc b/src/cobalt/script/mozjs/mozjs_engine.cc
index 623a7e5..7b62f3f 100644
--- a/src/cobalt/script/mozjs/mozjs_engine.cc
+++ b/src/cobalt/script/mozjs/mozjs_engine.cc
@@ -18,6 +18,7 @@
#include <algorithm>
+#include "base/debug/trace_event.h"
#include "base/logging.h"
#include "cobalt/base/c_val.h"
#include "cobalt/browser/stack_size_constants.h"
@@ -101,6 +102,7 @@
} // namespace
MozjsEngine::MozjsEngine() : accumulated_extra_memory_cost_(0) {
+ TRACE_EVENT0("cobalt::script", "MozjsEngine::MozjsEngine()");
// TODO: Investigate the benefit of helper threads and things like
// parallel compilation.
runtime_ =
@@ -147,11 +149,13 @@
}
scoped_refptr<GlobalEnvironment> MozjsEngine::CreateGlobalEnvironment() {
+ TRACE_EVENT0("cobalt::script", "MozjsEngine::CreateGlobalEnvironment()");
DCHECK(thread_checker_.CalledOnValidThread());
return new MozjsGlobalEnvironment(runtime_);
}
void MozjsEngine::CollectGarbage() {
+ TRACE_EVENT0("cobalt::script", "MozjsEngine::CollectGarbage()");
DCHECK(thread_checker_.CalledOnValidThread());
JS_GC(runtime_);
}
@@ -196,15 +200,18 @@
MozjsGlobalEnvironment* global_environment =
MozjsGlobalEnvironment::GetFromContext(engine->contexts_[i]);
if (status == JSGC_BEGIN) {
+ TRACE_EVENT_BEGIN0("cobalt::script", "SpiderMonkey Garbage Collection");
global_environment->BeginGarbageCollection();
} else if (status == JSGC_END) {
global_environment->EndGarbageCollection();
+ TRACE_EVENT_END0("cobalt::script", "SpiderMonkey Garbage Collection");
}
}
}
void MozjsEngine::FinalizeCallback(JSFreeOp* free_op, JSFinalizeStatus status,
JSBool is_compartment) {
+ TRACE_EVENT0("cobalt::script", "MozjsEngine::FinalizeCallback()");
MozjsEngine* engine =
static_cast<MozjsEngine*>(JS_GetRuntimePrivate(free_op->runtime()));
DCHECK(engine->thread_checker_.CalledOnValidThread());
@@ -220,6 +227,7 @@
} // namespace mozjs
scoped_ptr<JavaScriptEngine> JavaScriptEngine::CreateEngine() {
+ TRACE_EVENT0("cobalt::script", "JavaScriptEngine::CreateEngine()");
return make_scoped_ptr<JavaScriptEngine>(new mozjs::MozjsEngine());
}
diff --git a/src/cobalt/script/mozjs/mozjs_global_environment.cc b/src/cobalt/script/mozjs/mozjs_global_environment.cc
index 89ddeb2..b9c05a9 100644
--- a/src/cobalt/script/mozjs/mozjs_global_environment.cc
+++ b/src/cobalt/script/mozjs/mozjs_global_environment.cc
@@ -28,6 +28,7 @@
#include "cobalt/script/mozjs/proxy_handler.h"
#include "cobalt/script/mozjs/referenced_object_map.h"
#include "cobalt/script/mozjs/util/exception_helpers.h"
+#include "nb/memory_scope.h"
#include "third_party/mozjs/js/src/jsfriendapi.h"
#include "third_party/mozjs/js/src/jsfun.h"
#include "third_party/mozjs/js/src/jsobj.h"
@@ -128,6 +129,7 @@
environment_settings_(NULL),
last_error_message_(NULL),
eval_enabled_(false) {
+ TRACK_MEMORY_SCOPE("Javascript");
context_ = JS_NewContext(runtime, kStackChunkSize);
DCHECK(context_);
// Set a pointer to this class inside the JSContext.
@@ -166,6 +168,7 @@
}
void MozjsGlobalEnvironment::CreateGlobalObject() {
+ TRACK_MEMORY_SCOPE("Javascript");
DCHECK(thread_checker_.CalledOnValidThread());
DCHECK(!global_object_proxy_);
@@ -194,6 +197,7 @@
bool MozjsGlobalEnvironment::EvaluateScript(
const scoped_refptr<SourceCode>& source_code,
std::string* out_result_utf8) {
+ TRACK_MEMORY_SCOPE("Javascript");
DCHECK(thread_checker_.CalledOnValidThread());
JSAutoRequest auto_request(context_);
@@ -225,6 +229,7 @@
const scoped_refptr<SourceCode>& source_code,
const scoped_refptr<Wrappable>& owning_object,
base::optional<OpaqueHandleHolder::Reference>* out_opaque_handle) {
+ TRACK_MEMORY_SCOPE("Javascript");
DCHECK(thread_checker_.CalledOnValidThread());
JSAutoRequest auto_request(context_);
JSAutoCompartment auto_compartment(context_, global_object_proxy_);
@@ -245,6 +250,7 @@
bool MozjsGlobalEnvironment::EvaluateScriptInternal(
const scoped_refptr<SourceCode>& source_code,
JS::MutableHandleValue out_result) {
+ TRACK_MEMORY_SCOPE("Javascript");
DCHECK(thread_checker_.CalledOnValidThread());
DCHECK(global_object_proxy_);
MozjsSourceCode* mozjs_source_code =
@@ -291,6 +297,7 @@
void MozjsGlobalEnvironment::AllowGarbageCollection(
const scoped_refptr<Wrappable>& wrappable) {
+ TRACK_MEMORY_SCOPE("Javascript");
DCHECK(thread_checker_.CalledOnValidThread());
CachedWrapperMultiMap::iterator it =
kept_alive_objects_.find(wrappable.get());
@@ -320,6 +327,7 @@
void MozjsGlobalEnvironment::Bind(const std::string& identifier,
const scoped_refptr<Wrappable>& impl) {
+ TRACK_MEMORY_SCOPE("Javascript");
JSAutoRequest auto_request(context_);
JSAutoCompartment auto_compartment(context_, global_object_proxy_);
@@ -342,12 +350,14 @@
}
void MozjsGlobalEnvironment::DoSweep() {
+ TRACK_MEMORY_SCOPE("Javascript");
weak_object_manager_.SweepUnmarkedObjects();
// Remove NULL references after sweeping weak references.
referenced_objects_->RemoveNullReferences();
}
void MozjsGlobalEnvironment::BeginGarbageCollection() {
+ TRACK_MEMORY_SCOPE("Javascript");
// It's possible that a GC could be triggered from within the
// BeginGarbageCollection callback. Only create the OpaqueRootState the first
// time we enter.
@@ -461,6 +471,7 @@
}
JSBool MozjsGlobalEnvironment::CheckEval(JSContext* context) {
+ TRACK_MEMORY_SCOPE("Javascript");
MozjsGlobalEnvironment* global_object_proxy = GetFromContext(context);
DCHECK(global_object_proxy);
if (!global_object_proxy->report_eval_.is_null()) {
diff --git a/src/cobalt/script/mozjs/util/exception_helpers.cc b/src/cobalt/script/mozjs/util/exception_helpers.cc
index ce0ca06..3a4b80c 100644
--- a/src/cobalt/script/mozjs/util/exception_helpers.cc
+++ b/src/cobalt/script/mozjs/util/exception_helpers.cc
@@ -28,6 +28,25 @@
namespace script {
namespace mozjs {
namespace util {
+std::string GetExceptionString(JSContext* context) {
+ if (!JS_IsExceptionPending(context)) {
+ return std::string("No exception pending.");
+ }
+ JS::RootedValue exception(context);
+ JS_GetPendingException(context, exception.address());
+ JS_ReportPendingException(context);
+ return GetExceptionString(context, exception);
+}
+
+std::string GetExceptionString(JSContext* context,
+ JS::HandleValue exception) {
+ std::string exception_string;
+ MozjsExceptionState exception_state(context);
+ FromJSValue(context, exception, kNoConversionFlags, &exception_state,
+ &exception_string);
+ return exception_string;
+}
+
std::vector<StackFrame> GetStackTrace(JSContext* context, int max_frames) {
JSAutoRequest auto_request(context);
JS::StackDescription* stack_description =
diff --git a/src/cobalt/script/mozjs/util/exception_helpers.h b/src/cobalt/script/mozjs/util/exception_helpers.h
index 75dff27..7e5e563 100644
--- a/src/cobalt/script/mozjs/util/exception_helpers.h
+++ b/src/cobalt/script/mozjs/util/exception_helpers.h
@@ -16,6 +16,7 @@
#ifndef COBALT_SCRIPT_MOZJS_UTIL_EXCEPTION_HELPERS_H_
#define COBALT_SCRIPT_MOZJS_UTIL_EXCEPTION_HELPERS_H_
+#include <string>
#include <vector>
#include "cobalt/script/stack_frame.h"
@@ -25,6 +26,10 @@
namespace script {
namespace mozjs {
namespace util {
+std::string GetExceptionString(JSContext* context);
+
+std::string GetExceptionString(JSContext* context, JS::HandleValue exception);
+
std::vector<StackFrame> GetStackTrace(JSContext* context, int max_frames);
} // namespace util
} // namespace mozjs
diff --git a/src/cobalt/script/script.gyp b/src/cobalt/script/script.gyp
index c827de2..46cc245 100644
--- a/src/cobalt/script/script.gyp
+++ b/src/cobalt/script/script.gyp
@@ -38,6 +38,7 @@
],
'dependencies': [
'<(DEPTH)/cobalt/base/base.gyp:base',
+ '<(DEPTH)/nb/nb.gyp:nb',
]
},
{
diff --git a/src/cobalt/speech/microphone_manager.cc b/src/cobalt/speech/microphone_manager.cc
index ea3ba7d..4414a77 100644
--- a/src/cobalt/speech/microphone_manager.cc
+++ b/src/cobalt/speech/microphone_manager.cc
@@ -16,12 +16,6 @@
#include "cobalt/speech/microphone_manager.h"
-#if defined(ENABLE_FAKE_MICROPHONE)
-#include "cobalt/speech/microphone_fake.h"
-#endif // defined(ENABLE_FAKE_MICROPHONE)
-#if defined(SB_USE_SB_MICROPHONE)
-#include "cobalt/speech/microphone_starboard.h"
-#endif // defined(SB_USE_SB_MICROPHONE)
#include "cobalt/speech/speech_recognition_error.h"
namespace cobalt {
@@ -34,26 +28,16 @@
const float kMicReadRateInHertz = 60.0f;
} // namespace
-MicrophoneManager::MicrophoneManager(int sample_rate,
- const DataReceivedCallback& data_received,
- const CompletionCallback& completion,
- const ErrorCallback& error,
- const Microphone::Options& options)
- : sample_rate_(sample_rate),
- data_received_callback_(data_received),
+MicrophoneManager::MicrophoneManager(
+ const DataReceivedCallback& data_received,
+ const CompletionCallback& completion, const ErrorCallback& error,
+ const MicrophoneCreator& microphone_creator)
+ : data_received_callback_(data_received),
completion_callback_(completion),
error_callback_(error),
-#if defined(ENABLE_FAKE_MICROPHONE)
- microphone_options_(options),
-#endif // defined(ENABLE_FAKE_MICROPHONE)
+ microphone_creator_(microphone_creator),
state_(kStopped),
thread_("microphone_thread") {
- UNREFERENCED_PARAMETER(sample_rate_);
-#if defined(ENABLE_FAKE_MICROPHONE)
- UNREFERENCED_PARAMETER(microphone_options_);
-#else
- UNREFERENCED_PARAMETER(options);
-#endif // defined(ENABLE_FAKE_MICROPHONE)
thread_.StartWithOptions(base::Thread::Options(MessageLoop::TYPE_IO, 0));
}
@@ -82,19 +66,7 @@
return true;
}
-#if defined(SB_USE_SB_MICROPHONE)
-#if defined(ENABLE_FAKE_MICROPHONE)
- if (microphone_options_.enable_fake_microphone) {
- microphone_.reset(new MicrophoneFake(microphone_options_));
- } else {
- microphone_.reset(
- new MicrophoneStarboard(sample_rate_, kBufferSizeInBytes));
- }
-#else
- microphone_.reset(new MicrophoneStarboard(sample_rate_, kBufferSizeInBytes));
-#endif // defined(ENABLE_FAKE_MICROPHONE)
-#endif // defined(SB_USE_SB_MICROPHONE)
-
+ microphone_ = microphone_creator_.Run(kBufferSizeInBytes);
if (microphone_ && microphone_->IsValid()) {
state_ = kStopped;
return true;
@@ -163,7 +135,7 @@
DCHECK(microphone_);
DCHECK(microphone_->MinMicrophoneReadInBytes() <= kBufferSizeInBytes);
- static int16_t samples[kBufferSizeInBytes / sizeof(int16_t)];
+ int16_t samples[kBufferSizeInBytes / sizeof(int16_t)];
int read_bytes =
microphone_->Read(reinterpret_cast<char*>(samples), kBufferSizeInBytes);
// If |read_bytes| is zero, nothing should happen.
diff --git a/src/cobalt/speech/microphone_manager.h b/src/cobalt/speech/microphone_manager.h
index c07c21a..08eaf6e 100644
--- a/src/cobalt/speech/microphone_manager.h
+++ b/src/cobalt/speech/microphone_manager.h
@@ -38,11 +38,12 @@
typedef base::Callback<void(scoped_ptr<ShellAudioBus>)> DataReceivedCallback;
typedef base::Callback<void(void)> CompletionCallback;
typedef base::Callback<void(const scoped_refptr<dom::Event>&)> ErrorCallback;
+ typedef base::Callback<scoped_ptr<Microphone>(int)> MicrophoneCreator;
- MicrophoneManager(int sample_rate, const DataReceivedCallback& data_received,
+ MicrophoneManager(const DataReceivedCallback& data_received,
const CompletionCallback& completion,
const ErrorCallback& error,
- const Microphone::Options& options);
+ const MicrophoneCreator& microphone_creator);
~MicrophoneManager();
@@ -65,15 +66,12 @@
// Timer callback for fetching audio data.
void Read();
- int sample_rate_;
const DataReceivedCallback data_received_callback_;
const CompletionCallback completion_callback_;
const ErrorCallback error_callback_;
+ const MicrophoneCreator microphone_creator_;
scoped_ptr<Microphone> microphone_;
-#if defined(ENABLE_FAKE_MICROPHONE)
- Microphone::Options microphone_options_;
-#endif // defined(ENABLE_FAKE_MICROPHONE)
// Microphone state.
State state_;
diff --git a/src/cobalt/speech/speech.gyp b/src/cobalt/speech/speech.gyp
index 4d431dd..c016372 100644
--- a/src/cobalt/speech/speech.gyp
+++ b/src/cobalt/speech/speech.gyp
@@ -77,6 +77,8 @@
'sources': [
'microphone_fake.cc',
'microphone_fake.h',
+ 'url_fetcher_fake.cc',
+ 'url_fetcher_fake.h',
],
'defines': [
'ENABLE_FAKE_MICROPHONE',
diff --git a/src/cobalt/speech/speech_recognition_manager.cc b/src/cobalt/speech/speech_recognition_manager.cc
index 0b4ffdf..4eab7de 100644
--- a/src/cobalt/speech/speech_recognition_manager.cc
+++ b/src/cobalt/speech/speech_recognition_manager.cc
@@ -19,7 +19,15 @@
#include "base/bind.h"
#include "cobalt/base/tokens.h"
#include "cobalt/dom/dom_exception.h"
+#if defined(ENABLE_FAKE_MICROPHONE)
+#include "cobalt/speech/microphone_fake.h"
+#include "cobalt/speech/url_fetcher_fake.h"
+#endif // defined(ENABLE_FAKE_MICROPHONE)
#include "cobalt/speech/microphone_manager.h"
+#if defined(SB_USE_SB_MICROPHONE)
+#include "cobalt/speech/microphone_starboard.h"
+#endif // defined(SB_USE_SB_MICROPHONE)
+#include "net/url_request/url_fetcher.h"
namespace cobalt {
namespace speech {
@@ -27,6 +35,40 @@
namespace {
const int kSampleRate = 16000;
const float kAudioPacketDurationInSeconds = 0.1f;
+
+scoped_ptr<net::URLFetcher> CreateURLFetcher(
+ const GURL& url, net::URLFetcher::RequestType request_type,
+ net::URLFetcherDelegate* delegate) {
+ return make_scoped_ptr<net::URLFetcher>(
+ net::URLFetcher::Create(url, request_type, delegate));
+}
+
+scoped_ptr<Microphone> CreateMicrophone(int buffer_size_bytes) {
+#if defined(SB_USE_SB_MICROPHONE)
+ return make_scoped_ptr<Microphone>(
+ new MicrophoneStarboard(kSampleRate, buffer_size_bytes));
+#else
+ UNREFERENCED_PARAMETER(buffer_size_bytes);
+ return scoped_ptr<Microphone>();
+#endif // defined(SB_USE_SB_MICROPHONE)
+}
+
+#if defined(SB_USE_SB_MICROPHONE)
+#if defined(ENABLE_FAKE_MICROPHONE)
+scoped_ptr<net::URLFetcher> CreateFakeURLFetcher(
+ const GURL& url, net::URLFetcher::RequestType request_type,
+ net::URLFetcherDelegate* delegate) {
+ return make_scoped_ptr<net::URLFetcher>(
+ new URLFetcherFake(url, request_type, delegate));
+}
+
+scoped_ptr<Microphone> CreateFakeMicrophone(const Microphone::Options& options,
+ int /*buffer_size_bytes*/) {
+ return make_scoped_ptr<Microphone>(new MicrophoneFake(options));
+}
+#endif // defined(ENABLE_FAKE_MICROPHONE)
+#endif // defined(SB_USE_SB_MICROPHONE)
+
} // namespace
SpeechRecognitionManager::SpeechRecognitionManager(
@@ -36,20 +78,38 @@
weak_this_(weak_ptr_factory_.GetWeakPtr()),
main_message_loop_(base::MessageLoopProxy::current()),
event_callback_(event_callback),
- ALLOW_THIS_IN_INITIALIZER_LIST(
- recognizer_(network_module,
- base::Bind(&SpeechRecognitionManager::OnRecognizerEvent,
- base::Unretained(this)))),
- ALLOW_THIS_IN_INITIALIZER_LIST(microphone_manager_(new MicrophoneManager(
- kSampleRate, base::Bind(&SpeechRecognitionManager::OnDataReceived,
- base::Unretained(this)),
- base::Bind(&SpeechRecognitionManager::OnDataCompletion,
- base::Unretained(this)),
- base::Bind(&SpeechRecognitionManager::OnMicError,
- base::Unretained(this)),
- microphone_options))),
endpointer_delegate_(kSampleRate),
- state_(kStopped) {}
+ state_(kStopped) {
+ UNREFERENCED_PARAMETER(microphone_options);
+
+ SpeechRecognizer::URLFetcherCreator url_fetcher_creator =
+ base::Bind(&CreateURLFetcher);
+ MicrophoneManager::MicrophoneCreator microphone_creator =
+ base::Bind(&CreateMicrophone);
+
+#if defined(SB_USE_SB_MICROPHONE)
+#if defined(ENABLE_FAKE_MICROPHONE)
+ if (microphone_options.enable_fake_microphone) {
+ // If fake microphone is enabled, fake URL fetchers should be enabled as
+ // well.
+ url_fetcher_creator = base::Bind(&CreateFakeURLFetcher);
+ microphone_creator = base::Bind(&CreateFakeMicrophone, microphone_options);
+ }
+#endif // defined(ENABLE_FAKE_MICROPHONE)
+#endif // defined(SB_USE_SB_MICROPHONE)
+
+ recognizer_.reset(new SpeechRecognizer(
+ network_module, base::Bind(&SpeechRecognitionManager::OnRecognizerEvent,
+ base::Unretained(this)),
+ url_fetcher_creator));
+ microphone_manager_.reset(new MicrophoneManager(
+ base::Bind(&SpeechRecognitionManager::OnDataReceived,
+ base::Unretained(this)),
+ base::Bind(&SpeechRecognitionManager::OnDataCompletion,
+ base::Unretained(this)),
+ base::Bind(&SpeechRecognitionManager::OnMicError, base::Unretained(this)),
+ microphone_creator));
+}
SpeechRecognitionManager::~SpeechRecognitionManager() { Stop(); }
@@ -65,7 +125,7 @@
return;
}
- recognizer_.Start(config, kSampleRate);
+ recognizer_->Start(config, kSampleRate);
microphone_manager_->Open();
endpointer_delegate_.Start();
state_ = kStarted;
@@ -82,7 +142,7 @@
endpointer_delegate_.Stop();
microphone_manager_->Close();
- recognizer_.Stop();
+ recognizer_->Stop();
state_ = kStopped;
event_callback_.Run(new dom::Event(base::Tokens::soundend()));
}
@@ -98,7 +158,7 @@
endpointer_delegate_.Stop();
microphone_manager_->Close();
- recognizer_.Stop();
+ recognizer_->Stop();
state_ = kAborted;
event_callback_.Run(new dom::Event(base::Tokens::soundend()));
}
@@ -118,7 +178,7 @@
if (endpointer_delegate_.IsFirstTimeSoundStarted(*audio_bus)) {
event_callback_.Run(new dom::Event(base::Tokens::soundstart()));
}
- recognizer_.RecognizeAudio(audio_bus.Pass(), false);
+ recognizer_->RecognizeAudio(audio_bus.Pass(), false);
}
}
@@ -140,7 +200,7 @@
scoped_ptr<ShellAudioBus> dummy_audio_bus(new ShellAudioBus(
1, dummy_frames, ShellAudioBus::kInt16, ShellAudioBus::kInterleaved));
dummy_audio_bus->ZeroAllFrames();
- recognizer_.RecognizeAudio(dummy_audio_bus.Pass(), true);
+ recognizer_->RecognizeAudio(dummy_audio_bus.Pass(), true);
}
}
@@ -174,7 +234,7 @@
// An error is occured in Mic, so stop the energy endpointer and recognizer.
endpointer_delegate_.Stop();
- recognizer_.Stop();
+ recognizer_->Stop();
state_ = kAborted;
event_callback_.Run(new dom::Event(base::Tokens::soundend()));
}
diff --git a/src/cobalt/speech/speech_recognition_manager.h b/src/cobalt/speech/speech_recognition_manager.h
index 6f0faa7..2d622dd 100644
--- a/src/cobalt/speech/speech_recognition_manager.h
+++ b/src/cobalt/speech/speech_recognition_manager.h
@@ -80,7 +80,7 @@
// Callback for sending dom events if available.
EventCallback event_callback_;
- SpeechRecognizer recognizer_;
+ scoped_ptr<SpeechRecognizer> recognizer_;
scoped_ptr<MicrophoneManager> microphone_manager_;
diff --git a/src/cobalt/speech/speech_recognizer.cc b/src/cobalt/speech/speech_recognizer.cc
index 902fd48..17806b8 100644
--- a/src/cobalt/speech/speech_recognizer.cc
+++ b/src/cobalt/speech/speech_recognizer.cc
@@ -164,10 +164,12 @@
} // namespace
SpeechRecognizer::SpeechRecognizer(network::NetworkModule* network_module,
- const EventCallback& event_callback)
+ const EventCallback& event_callback,
+ const URLFetcherCreator& fetcher_creator)
: network_module_(network_module),
started_(false),
event_callback_(event_callback),
+ fetcher_creator_(fetcher_creator),
thread_("speech_recognizer") {
thread_.StartWithOptions(base::Thread::Options(MessageLoop::TYPE_IO, 0));
}
@@ -264,8 +266,8 @@
// Use protobuffer as the output format.
down_url = AppendQueryParameter(down_url, "output", "pb");
- downstream_fetcher_.reset(
- net::URLFetcher::Create(down_url, net::URLFetcher::GET, this));
+ downstream_fetcher_ =
+ fetcher_creator_.Run(down_url, net::URLFetcher::GET, this);
downstream_fetcher_->SetRequestContext(
network_module_->url_request_context_getter());
downstream_fetcher_->Start();
@@ -312,8 +314,7 @@
up_url = AppendQueryParameter(up_url, "interim", "");
}
- upstream_fetcher_.reset(
- net::URLFetcher::Create(up_url, net::URLFetcher::POST, this));
+ upstream_fetcher_ = fetcher_creator_.Run(up_url, net::URLFetcher::POST, this);
upstream_fetcher_->SetRequestContext(
network_module_->url_request_context_getter());
upstream_fetcher_->SetChunkedUpload(encoder_->GetMimeType());
diff --git a/src/cobalt/speech/speech_recognizer.h b/src/cobalt/speech/speech_recognizer.h
index 55cd68f..5dac2c6 100644
--- a/src/cobalt/speech/speech_recognizer.h
+++ b/src/cobalt/speech/speech_recognizer.h
@@ -46,9 +46,13 @@
typedef base::Callback<void(const scoped_refptr<dom::Event>&)> EventCallback;
typedef SpeechRecognitionResultList::SpeechRecognitionResults
SpeechRecognitionResults;
+ typedef base::Callback<scoped_ptr<net::URLFetcher>(
+ const GURL&, net::URLFetcher::RequestType, net::URLFetcherDelegate*)>
+ URLFetcherCreator;
SpeechRecognizer(network::NetworkModule* network_module,
- const EventCallback& event_callback);
+ const EventCallback& event_callback,
+ const URLFetcherCreator& fetcher_creator);
~SpeechRecognizer() OVERRIDE;
// Multiple calls to Start/Stop are allowed, the implementation should take
@@ -86,7 +90,10 @@
scoped_ptr<net::URLFetcher> upstream_fetcher_;
// Fetcher for receiving the streaming results.
scoped_ptr<net::URLFetcher> downstream_fetcher_;
- EventCallback event_callback_;
+ // Used to send speech recognition event.
+ const EventCallback event_callback_;
+ // Used to create url fetcher.
+ const URLFetcherCreator fetcher_creator_;
// Used for processing proto buffer data.
content::ChunkedByteBuffer chunked_byte_buffer_;
// Used for accumulating final results.
diff --git a/src/cobalt/speech/url_fetcher_fake.cc b/src/cobalt/speech/url_fetcher_fake.cc
new file mode 100644
index 0000000..2d621cb
--- /dev/null
+++ b/src/cobalt/speech/url_fetcher_fake.cc
@@ -0,0 +1,176 @@
+/*
+ * Copyright 2016 Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "cobalt/speech/url_fetcher_fake.h"
+
+#if defined(ENABLE_FAKE_MICROPHONE)
+
+#include "base/basictypes.h"
+#include "base/sys_byteorder.h"
+#include "cobalt/speech/google_streaming_api.pb.h"
+#include "net/url_request/url_fetcher_delegate.h"
+
+namespace cobalt {
+namespace speech {
+namespace {
+const int kDownloadTimerInterval = 100;
+
+struct RecognitionAlternative {
+ const char* transcript;
+ float confidence;
+};
+
+const RecognitionAlternative kAlternatives_1[] = {
+ {"tube", 0.0f},
+};
+
+const RecognitionAlternative kAlternatives_2[] = {
+ {"to be", 0.0f},
+};
+
+const RecognitionAlternative kAlternatives_3[] = {
+ {" or not", 0.0f},
+};
+
+const RecognitionAlternative kAlternatives_4[] = {
+ {" or not to be", 0.0f}, {"to be", 0.0f},
+};
+
+const RecognitionAlternative kAlternatives_5[] = {
+ {"to be or not to be", 0.728f}, {"2 B or not to be", 0.0f},
+};
+
+const RecognitionAlternative kAlternatives_6[] = {
+ {"that", 0.0f}, {"is the", 0.0f},
+};
+
+const RecognitionAlternative kAlternatives_7[] = {
+ {"that", 0.0f}, {"is the question", 0.0f},
+};
+
+const RecognitionAlternative kAlternatives_8[] = {
+ {"that is", 0.0f}, {"the question", 0.0f},
+};
+
+const RecognitionAlternative kAlternatives_9[] = {
+ {"that is the question", 0.8577f}, {"that is a question", 0.0f},
+};
+
+struct RecognitionResult {
+ const RecognitionAlternative* alternatives;
+ bool final;
+ size_t number_of_alternatives;
+};
+
+const RecognitionResult kRecognitionResults[] = {
+ {kAlternatives_1, false, SB_ARRAY_SIZE_INT(kAlternatives_1)},
+ {kAlternatives_2, false, SB_ARRAY_SIZE_INT(kAlternatives_2)},
+ {kAlternatives_3, false, SB_ARRAY_SIZE_INT(kAlternatives_3)},
+ {kAlternatives_4, false, SB_ARRAY_SIZE_INT(kAlternatives_4)},
+ {kAlternatives_5, true, SB_ARRAY_SIZE_INT(kAlternatives_5)},
+ {kAlternatives_6, false, SB_ARRAY_SIZE_INT(kAlternatives_6)},
+ {kAlternatives_7, false, SB_ARRAY_SIZE_INT(kAlternatives_7)},
+ {kAlternatives_8, false, SB_ARRAY_SIZE_INT(kAlternatives_8)},
+ {kAlternatives_9, true, SB_ARRAY_SIZE_INT(kAlternatives_9)},
+};
+
+std::string GetMockProtoResult(int index) {
+ proto::SpeechRecognitionEvent proto_event;
+ proto_event.set_status(proto::SpeechRecognitionEvent::STATUS_SUCCESS);
+ proto::SpeechRecognitionResult* proto_result = proto_event.add_result();
+ proto_result->set_final(kRecognitionResults[index].final);
+ const RecognitionAlternative* recognition_alternatives =
+ kRecognitionResults[index].alternatives;
+
+ for (size_t i = 0; i < kRecognitionResults[index].number_of_alternatives;
+ ++i) {
+ proto::SpeechRecognitionAlternative* proto_alternative =
+ proto_result->add_alternative();
+ proto_alternative->set_confidence(recognition_alternatives[i].confidence);
+ proto_alternative->set_transcript(recognition_alternatives[i].transcript);
+ }
+
+ std::string response_string;
+ proto_event.SerializeToString(&response_string);
+
+ // Prepend 4 byte prefix length indication to the protobuf message as
+ // envisaged by the google streaming recognition webservice protocol.
+ uint32_t prefix =
+ base::HostToNet32(static_cast<uint32_t>(response_string.size()));
+ response_string.insert(0, reinterpret_cast<char*>(&prefix), sizeof(prefix));
+ return response_string;
+}
+
+} // namespace
+
+URLFetcherFake::URLFetcherFake(const GURL& url,
+ net::URLFetcher::RequestType /*request_type*/,
+ net::URLFetcherDelegate* delegate)
+ : original_url_(url),
+ delegate_(delegate),
+ is_chunked_upload_(false),
+ download_index_(0) {}
+
+URLFetcherFake::~URLFetcherFake() {}
+
+void URLFetcherFake::SetChunkedUpload(
+ const std::string& /*upload_content_type*/) {
+ is_chunked_upload_ = true;
+}
+
+void URLFetcherFake::AppendChunkToUpload(const std::string& /*data*/,
+ bool /*is_last_chunk*/) {
+ SB_DCHECK(is_chunked_upload_);
+ // no-op.
+}
+
+void URLFetcherFake::SetRequestContext(
+ net::URLRequestContextGetter* /*request_context_getter*/) {
+ // no-op.
+}
+
+void URLFetcherFake::Start() {
+ if (!is_chunked_upload_) {
+ download_timer_.emplace();
+ download_timer_->Start(
+ FROM_HERE, base::TimeDelta::FromMilliseconds(kDownloadTimerInterval),
+ this, &URLFetcherFake::OnURLFetchDownloadData);
+ }
+}
+
+const net::URLRequestStatus& URLFetcherFake::GetStatus() const {
+ return fake_status_;
+}
+
+int URLFetcherFake::GetResponseCode() const { return 200; }
+
+void URLFetcherFake::OnURLFetchDownloadData() {
+ SB_DCHECK(!is_chunked_upload_);
+ std::string result = GetMockProtoResult(download_index_);
+ delegate_->OnURLFetchDownloadData(
+ this, make_scoped_ptr<std::string>(new std::string(result)));
+ download_index_++;
+ if (download_index_ ==
+ static_cast<int>(SB_ARRAY_SIZE_INT(kRecognitionResults))) {
+ download_index_ = 0;
+ download_timer_->Stop();
+ }
+}
+
+} // namespace speech
+} // namespace cobalt
+
+#endif // defined(ENABLE_FAKE_MICROPHONE)
diff --git a/src/cobalt/speech/url_fetcher_fake.h b/src/cobalt/speech/url_fetcher_fake.h
new file mode 100644
index 0000000..cf3c150
--- /dev/null
+++ b/src/cobalt/speech/url_fetcher_fake.h
@@ -0,0 +1,156 @@
+/*
+ * Copyright 2016 Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef COBALT_SPEECH_URL_FETCHER_FAKE_H_
+#define COBALT_SPEECH_URL_FETCHER_FAKE_H_
+
+#include "cobalt/speech/speech_configuration.h"
+
+#if defined(ENABLE_FAKE_MICROPHONE)
+
+#include <string>
+
+#include "base/optional.h"
+#include "base/timer.h"
+#include "googleurl/src/gurl.h"
+#include "net/base/host_port_pair.h"
+#include "net/url_request/url_fetcher.h"
+#include "net/url_request/url_request_status.h"
+
+namespace cobalt {
+namespace speech {
+
+class URLFetcherFake : public net::URLFetcher {
+ public:
+ URLFetcherFake(const GURL& url, net::URLFetcher::RequestType request_type,
+ net::URLFetcherDelegate* delegate);
+ virtual ~URLFetcherFake();
+
+ // URLFetcher implementation:
+ void SetUploadData(const std::string& /*upload_content_type*/,
+ const std::string& /*upload_content*/) OVERRIDE {
+ NOTREACHED();
+ }
+ void SetChunkedUpload(const std::string& /*upload_content_type*/) OVERRIDE;
+ void AppendChunkToUpload(const std::string& data,
+ bool is_last_chunk) OVERRIDE;
+ void SetLoadFlags(int /*load_flags*/) OVERRIDE { NOTREACHED(); }
+ int GetLoadFlags() const OVERRIDE {
+ NOTREACHED();
+ return 0;
+ }
+ void SetReferrer(const std::string& /*referrer*/) OVERRIDE { NOTREACHED(); }
+ void SetExtraRequestHeaders(
+ const std::string& /*extra_request_headers*/) OVERRIDE {
+ NOTREACHED();
+ }
+ void AddExtraRequestHeader(const std::string& /*header_line*/) OVERRIDE {
+ NOTREACHED();
+ }
+ void GetExtraRequestHeaders(
+ net::HttpRequestHeaders* /*headers*/) const OVERRIDE {
+ NOTREACHED();
+ }
+ void SetRequestContext(
+ net::URLRequestContextGetter* request_context_getter) OVERRIDE;
+ void SetFirstPartyForCookies(
+ const GURL& /*first_party_for_cookies*/) OVERRIDE {
+ NOTREACHED();
+ }
+ void SetURLRequestUserData(
+ const void* /*key*/,
+ const CreateDataCallback& /*create_data_callback*/) OVERRIDE {
+ NOTREACHED();
+ }
+ void SetStopOnRedirect(bool /*stop_on_redirect*/) OVERRIDE { NOTREACHED(); }
+ void SetAutomaticallyRetryOn5xx(bool /*retry*/) OVERRIDE { NOTREACHED(); }
+ void SetMaxRetriesOn5xx(int /*max_retries*/) OVERRIDE { NOTREACHED(); }
+ int GetMaxRetriesOn5xx() const OVERRIDE {
+ NOTREACHED();
+ return 0;
+ }
+ base::TimeDelta GetBackoffDelay() const OVERRIDE {
+ NOTREACHED();
+ return base::TimeDelta();
+ }
+ void SetAutomaticallyRetryOnNetworkChanges(int /*max_retries*/) OVERRIDE {
+ NOTREACHED();
+ }
+ void SaveResponseToFileAtPath(
+ const FilePath& /*file_path*/,
+ scoped_refptr<base::TaskRunner> /*file_task_runner*/) OVERRIDE {
+ NOTREACHED();
+ }
+ void SaveResponseToTemporaryFile(
+ scoped_refptr<base::TaskRunner> /*file_task_runner*/) OVERRIDE {
+ NOTREACHED();
+ }
+ void DiscardResponse() OVERRIDE { NOTREACHED(); }
+ net::HttpResponseHeaders* GetResponseHeaders() const OVERRIDE {
+ NOTREACHED();
+ return NULL;
+ }
+ net::HostPortPair GetSocketAddress() const OVERRIDE {
+ NOTREACHED();
+ return net::HostPortPair();
+ }
+ bool WasFetchedViaProxy() const OVERRIDE {
+ NOTREACHED();
+ return false;
+ }
+ void Start() OVERRIDE;
+ const GURL& GetOriginalURL() const OVERRIDE { return original_url_; }
+ const GURL& GetURL() const OVERRIDE { return original_url_; }
+ const net::URLRequestStatus& GetStatus() const OVERRIDE;
+ int GetResponseCode() const OVERRIDE;
+ const net::ResponseCookies& GetCookies() const OVERRIDE {
+ NOTREACHED();
+ return fake_cookies_;
+ }
+ bool FileErrorOccurred(
+ base::PlatformFileError* /*out_error_code*/) const OVERRIDE {
+ NOTREACHED();
+ return false;
+ }
+ void ReceivedContentWasMalformed() OVERRIDE { NOTREACHED(); }
+ bool GetResponseAsString(
+ std::string* /*out_response_string*/) const OVERRIDE {
+ NOTREACHED();
+ return false;
+ }
+ bool GetResponseAsFilePath(bool /*take_ownership*/,
+ FilePath* /*out_response_path*/) const OVERRIDE {
+ NOTREACHED();
+ return false;
+ }
+
+ private:
+ void OnURLFetchDownloadData();
+
+ GURL original_url_;
+ net::URLFetcherDelegate* delegate_;
+ bool is_chunked_upload_;
+ int download_index_;
+ net::ResponseCookies fake_cookies_;
+ net::URLRequestStatus fake_status_;
+ base::optional<base::RepeatingTimer<URLFetcherFake> > download_timer_;
+};
+
+} // namespace speech
+} // namespace cobalt
+
+#endif // defined(ENABLE_FAKE_MICROPHONE)
+#endif // COBALT_SPEECH_URL_FETCHER_FAKE_H_
diff --git a/src/cobalt/storage/virtual_file.cc b/src/cobalt/storage/virtual_file.cc
index 64904c2..dcb93ed 100644
--- a/src/cobalt/storage/virtual_file.cc
+++ b/src/cobalt/storage/virtual_file.cc
@@ -87,7 +87,10 @@
buffer_.resize(offset + bytes);
}
- memcpy(&buffer_[offset], source, bytes);
+ if (!buffer_.empty()) {
+ // std::vector does not define access to underlying array when empty
+ memcpy(&buffer_[offset], source, bytes);
+ }
return bytes_in;
}
diff --git a/src/cobalt/system_window/starboard/system_window.cc b/src/cobalt/system_window/starboard/system_window.cc
index 331e028..2f1b24a 100644
--- a/src/cobalt/system_window/starboard/system_window.cc
+++ b/src/cobalt/system_window/starboard/system_window.cc
@@ -103,6 +103,15 @@
return math::Size(window_size.width, window_size.height);
}
+float SystemWindowStarboard::GetVideoPixelRatio() const {
+ SbWindowSize window_size;
+ if (!SbWindowGetSize(window_, &window_size)) {
+ DLOG(WARNING) << "SbWindowGetSize() failed.";
+ return 1.0;
+ }
+ return window_size.video_pixel_ratio;
+}
+
SbWindow SystemWindowStarboard::GetSbWindow() { return window_; }
void* SystemWindowStarboard::GetWindowHandle() {
diff --git a/src/cobalt/system_window/starboard/system_window.h b/src/cobalt/system_window/starboard/system_window.h
index 7d6a76e..b733bb9 100644
--- a/src/cobalt/system_window/starboard/system_window.h
+++ b/src/cobalt/system_window/starboard/system_window.h
@@ -36,6 +36,7 @@
~SystemWindowStarboard() OVERRIDE;
math::Size GetWindowSize() const OVERRIDE;
+ float GetVideoPixelRatio() const OVERRIDE;
// Returns a handle to the Starboard window object.
SbWindow GetSbWindow();
diff --git a/src/cobalt/system_window/system_window.h b/src/cobalt/system_window/system_window.h
index 4695652..82683e0 100644
--- a/src/cobalt/system_window/system_window.h
+++ b/src/cobalt/system_window/system_window.h
@@ -74,6 +74,11 @@
// Returns the dimensions of the window.
virtual math::Size GetWindowSize() const = 0;
+ // video pixel ratio = resolution of video output / resolution of window. Its
+ // value is usually 1.0. Set it to a value greater than 1.0 allows the video
+ // to be played in higher resolution than the window.
+ virtual float GetVideoPixelRatio() const { return 1.f; }
+
base::EventDispatcher* event_dispatcher() const { return event_dispatcher_; }
private:
diff --git a/src/cobalt/webdriver/element_driver.cc b/src/cobalt/webdriver/element_driver.cc
index 950581a..d295974 100644
--- a/src/cobalt/webdriver/element_driver.cc
+++ b/src/cobalt/webdriver/element_driver.cc
@@ -105,7 +105,7 @@
Keyboard::TranslateToKeyEvents(keys.utf8_keys(), Keyboard::kReleaseModifiers,
events.get());
// Dispatch the keyboard events.
- return util::CallOnMessageLoopWithRetry(
+ return util::CallOnMessageLoop(
element_message_loop_,
base::Bind(&ElementDriver::SendKeysInternal, base::Unretained(this),
base::Passed(&events)),
@@ -114,7 +114,7 @@
util::CommandResult<protocol::ElementId> ElementDriver::FindElement(
const protocol::SearchStrategy& strategy) {
- return util::CallOnMessageLoopWithRetry(
+ return util::CallOnMessageLoop(
element_message_loop_,
base::Bind(&ElementDriver::FindElementsInternal<protocol::ElementId>,
base::Unretained(this), strategy),
@@ -123,7 +123,7 @@
util::CommandResult<std::vector<protocol::ElementId> >
ElementDriver::FindElements(const protocol::SearchStrategy& strategy) {
- return util::CallOnMessageLoopWithRetry(
+ return util::CallOnMessageLoop(
element_message_loop_,
base::Bind(&ElementDriver::FindElementsInternal<ElementIdVector>,
base::Unretained(this), strategy),
@@ -132,7 +132,7 @@
util::CommandResult<bool> ElementDriver::Equals(
const ElementDriver* other_element_driver) {
- return util::CallOnMessageLoopWithRetry(
+ return util::CallOnMessageLoop(
element_message_loop_,
base::Bind(&ElementDriver::EqualsInternal, base::Unretained(this),
other_element_driver),
diff --git a/src/cobalt/webdriver/session_driver.cc b/src/cobalt/webdriver/session_driver.cc
index 91f3358..5a59853 100644
--- a/src/cobalt/webdriver/session_driver.cc
+++ b/src/cobalt/webdriver/session_driver.cc
@@ -28,6 +28,9 @@
// Default page-load timeout.
const int kPageLoadTimeoutInSeconds = 30;
+// Max retries for the "can_retry" CommandResult case.
+const int kMaxRetries = 5;
+
protocol::LogEntry::LogLevel SeverityToLogLevel(int severity) {
switch (severity) {
case logging::LOG_INFO:
@@ -82,7 +85,11 @@
}
util::CommandResult<void> SessionDriver::Navigate(const GURL& url) {
- util::CommandResult<void> result = window_driver_->Navigate(url);
+ int retries = 0;
+ util::CommandResult<void> result;
+ do {
+ result = window_driver_->Navigate(url);
+ } while (result.can_retry() && (retries++ < kMaxRetries));
if (result.is_success()) {
// TODO: Use timeout as specified by the webdriver client.
wait_for_navigation_.Run(
diff --git a/src/cobalt/webdriver/util/call_on_message_loop.h b/src/cobalt/webdriver/util/call_on_message_loop.h
index f3af96f..c2a19d2 100644
--- a/src/cobalt/webdriver/util/call_on_message_loop.h
+++ b/src/cobalt/webdriver/util/call_on_message_loop.h
@@ -123,24 +123,20 @@
}
// Tries to call |callback| on messageloop |message_loop_proxy|,
-// retrying a few times if the WebModule thread appears to have gone
-// away (perhaps because of navigation). If failure persists,
-// returns a CommandResult of |window_disappeared_code|.
+// but returns a CommandResult of |window_disappeared_code| if the
+// message loop has shut down. This can happen if a WebModule shuts
+// down due to a page navigation.
template <typename ReturnValue>
-util::CommandResult<ReturnValue> CallOnMessageLoopWithRetry(
+util::CommandResult<ReturnValue> CallOnMessageLoop(
const scoped_refptr<base::MessageLoopProxy>& message_loop_proxy,
const base::Callback<util::CommandResult<ReturnValue>(void)>& callback,
protocol::Response::StatusCode window_disappeared_code) {
util::CommandResult<ReturnValue> result;
-
- const int kRetryAttempts = 5;
- bool success = false;
- for (int i = 0; !success && i < kRetryAttempts; i++) {
- success = TryCallOnMessageLoop(message_loop_proxy, callback, &result);
- }
+ bool success = TryCallOnMessageLoop(message_loop_proxy, callback, &result);
if (!success) {
- result = util::CommandResult<ReturnValue>(window_disappeared_code);
+ result =
+ util::CommandResult<ReturnValue>(window_disappeared_code, "", true);
}
return result;
}
diff --git a/src/cobalt/webdriver/util/command_result.h b/src/cobalt/webdriver/util/command_result.h
index d1254c7..8944d4d 100644
--- a/src/cobalt/webdriver/util/command_result.h
+++ b/src/cobalt/webdriver/util/command_result.h
@@ -32,12 +32,17 @@
public:
CommandResult() : status_code_(protocol::Response::kUnknownError) {}
explicit CommandResult(protocol::Response::StatusCode status)
- : status_code_(status) {}
+ : status_code_(status), can_retry_(false) {}
CommandResult(protocol::Response::StatusCode status,
const std::string& message)
- : status_code_(status), error_message_(message) {}
+ : status_code_(status), error_message_(message), can_retry_(false) {}
+ CommandResult(protocol::Response::StatusCode status,
+ const std::string& message, bool can_retry)
+ : status_code_(status), error_message_(message), can_retry_(can_retry) {}
explicit CommandResult(const T& result)
- : status_code_(protocol::Response::kSuccess), result_(result) {}
+ : status_code_(protocol::Response::kSuccess),
+ result_(result),
+ can_retry_(false) {}
bool is_success() const {
return status_code_ == protocol::Response::kSuccess;
@@ -45,11 +50,16 @@
protocol::Response::StatusCode status_code() const { return status_code_; }
const T& result() const { return result_.value(); }
std::string error_message() const { return error_message_.value_or(""); }
+ // Returns true if this result occurred due to a transient issue,
+ // such as the WebModule going away. Retrying w/ a new WebModule
+ // may succeed.
+ bool can_retry() const { return can_retry_; }
private:
protocol::Response::StatusCode status_code_;
base::optional<T> result_;
base::optional<std::string> error_message_;
+ bool can_retry_;
};
template <>
@@ -57,20 +67,28 @@
public:
CommandResult() : status_code_(protocol::Response::kUnknownError) {}
explicit CommandResult(protocol::Response::StatusCode status)
- : status_code_(status) {}
+ : status_code_(status), can_retry_(false) {}
CommandResult(protocol::Response::StatusCode status,
const std::string& message)
- : status_code_(status), error_message_(message) {}
+ : status_code_(status), error_message_(message), can_retry_(false) {}
+ CommandResult(protocol::Response::StatusCode status,
+ const std::string& message, bool can_retry)
+ : status_code_(status), error_message_(message), can_retry_(can_retry) {}
bool is_success() const {
return status_code_ == protocol::Response::kSuccess;
}
protocol::Response::StatusCode status_code() const { return status_code_; }
std::string error_message() const { return error_message_.value_or(""); }
+ // Returns true if this result occurred due to a transient issue,
+ // such as the WebModule going away. Retrying w/ a new WebModule
+ // may succeed.
+ bool can_retry() const { return can_retry_; }
private:
protocol::Response::StatusCode status_code_;
base::optional<std::string> error_message_;
+ bool can_retry_;
};
} // namespace util
diff --git a/src/cobalt/webdriver/util/dispatch_command_factory.h b/src/cobalt/webdriver/util/dispatch_command_factory.h
index 1e45e4b..cfed299 100644
--- a/src/cobalt/webdriver/util/dispatch_command_factory.h
+++ b/src/cobalt/webdriver/util/dispatch_command_factory.h
@@ -122,6 +122,9 @@
template <class DriverClassT>
class DispatchCommandFactory
: public base::RefCounted<DispatchCommandFactory<DriverClassT> > {
+ // Max retries for the "can_retry" CommandResult case.
+ static const int kMaxRetries = 5;
+
public:
// Typedef'd for less verbose code.
typedef WebDriverDispatcher::CommandResultHandler CommandResultHandler;
@@ -220,7 +223,11 @@
DriverClassT* driver, const base::Value* parameters,
CommandResultHandler* result_handler) {
// Ignore parameters.
- util::CommandResult<R> command_result = driver_command.Run(driver);
+ int retries = 0;
+ util::CommandResult<R> command_result;
+ do {
+ command_result = driver_command.Run(driver);
+ } while (command_result.can_retry() && (retries++ < kMaxRetries));
internal::ReturnResponse(session_id, command_result, result_handler);
}
@@ -245,8 +252,11 @@
result_handler->SendInvalidRequestResponse(
WebDriverDispatcher::CommandResultHandler::kInvalidParameters, "");
} else {
- util::CommandResult<R> command_result =
- driver_command.Run(driver, param.value());
+ int retries = 0;
+ util::CommandResult<R> command_result;
+ do {
+ command_result = driver_command.Run(driver, param.value());
+ } while (command_result.can_retry() && (retries++ < kMaxRetries));
internal::ReturnResponse(session_id, command_result, result_handler);
}
}
diff --git a/src/cobalt/webdriver/window_driver.cc b/src/cobalt/webdriver/window_driver.cc
index 30c1415..b23abc2 100644
--- a/src/cobalt/webdriver/window_driver.cc
+++ b/src/cobalt/webdriver/window_driver.cc
@@ -162,7 +162,7 @@
util::CommandResult<void> WindowDriver::Navigate(const GURL& url) {
DCHECK(thread_checker_.CalledOnValidThread());
- return util::CallOnMessageLoopWithRetry(
+ return util::CallOnMessageLoop(
window_message_loop_,
base::Bind(&WindowDriver::NavigateInternal, base::Unretained(this), url),
protocol::Response::kNoSuchWindow);
@@ -190,7 +190,7 @@
const protocol::SearchStrategy& strategy) {
DCHECK(thread_checker_.CalledOnValidThread());
- return util::CallOnMessageLoopWithRetry(
+ return util::CallOnMessageLoop(
window_message_loop_,
base::Bind(&WindowDriver::FindElementsInternal<protocol::ElementId>,
base::Unretained(this), strategy),
@@ -200,7 +200,7 @@
util::CommandResult<std::vector<protocol::ElementId> >
WindowDriver::FindElements(const protocol::SearchStrategy& strategy) {
DCHECK(thread_checker_.CalledOnValidThread());
- return util::CallOnMessageLoopWithRetry(
+ return util::CallOnMessageLoop(
window_message_loop_,
base::Bind(&WindowDriver::FindElementsInternal<ElementIdVector>,
base::Unretained(this), strategy),
@@ -226,7 +226,7 @@
SyncExecuteResultHandler result_handler;
- CommandResult result = util::CallOnMessageLoopWithRetry(
+ CommandResult result = util::CallOnMessageLoop(
window_message_loop_,
base::Bind(&WindowDriver::ExecuteScriptInternal, base::Unretained(this),
script, base::nullopt, &result_handler),
@@ -249,7 +249,7 @@
const base::TimeDelta kDefaultAsyncTimeout =
base::TimeDelta::FromMilliseconds(0);
AsyncExecuteResultHandler result_handler;
- CommandResult result = util::CallOnMessageLoopWithRetry(
+ CommandResult result = util::CallOnMessageLoop(
window_message_loop_,
base::Bind(&WindowDriver::ExecuteScriptInternal, base::Unretained(this),
script, kDefaultAsyncTimeout, &result_handler),
@@ -274,7 +274,7 @@
Keyboard::TranslateToKeyEvents(keys.utf8_keys(), Keyboard::kKeepModifiers,
events.get());
// Dispatch the keyboard events.
- return util::CallOnMessageLoopWithRetry(
+ return util::CallOnMessageLoop(
window_message_loop_,
base::Bind(&WindowDriver::SendKeysInternal, base::Unretained(this),
base::Passed(&events)),
@@ -282,7 +282,7 @@
}
util::CommandResult<protocol::ElementId> WindowDriver::GetActiveElement() {
- return util::CallOnMessageLoopWithRetry(
+ return util::CallOnMessageLoop(
window_message_loop_, base::Bind(&WindowDriver::GetActiveElementInternal,
base::Unretained(this)),
protocol::Response::kNoSuchWindow);
@@ -330,10 +330,10 @@
util::CommandResult<void> WindowDriver::AddCookie(
const protocol::Cookie& cookie) {
DCHECK(thread_checker_.CalledOnValidThread());
- return util::CallOnMessageLoopWithRetry(
- window_message_loop_, base::Bind(&WindowDriver::AddCookieInternal,
- base::Unretained(this), cookie),
- protocol::Response::kNoSuchWindow);
+ return util::CallOnMessageLoop(window_message_loop_,
+ base::Bind(&WindowDriver::AddCookieInternal,
+ base::Unretained(this), cookie),
+ protocol::Response::kNoSuchWindow);
}
protocol::ElementId WindowDriver::ElementToId(
diff --git a/src/cobalt/webdriver_benchmarks/tv_testcase.py b/src/cobalt/webdriver_benchmarks/tv_testcase.py
index 57a7b77..c9a16ca 100644
--- a/src/cobalt/webdriver_benchmarks/tv_testcase.py
+++ b/src/cobalt/webdriver_benchmarks/tv_testcase.py
@@ -41,6 +41,11 @@
BASE_PARAMS = {"env_forcedOffAllExperiments": True}
PAGE_LOAD_WAIT_SECONDS = 30
LAYOUT_TIMEOUT_SECONDS = 5
+# Today, Cobalt's WebDriver has a race that
+# can leave the former page's DOM visible after a navigate.
+# As a workaround, sleep for a bit
+# b/33275371
+COBALT_POST_NAVIGATE_SLEEP_SECONDS = 5
def _percentile(results, percentile):
@@ -176,6 +181,7 @@
parsed_url[4] = urlencode(query_dict, doseq=True)
final_url = urlparse.urlunparse(parsed_url)
self.get_webdriver().get(final_url)
+ time.sleep(COBALT_POST_NAVIGATE_SLEEP_SECONDS)
def load_tv(self, label=None, additional_query_params=None):
"""Loads the main TV page and waits for it to display.
diff --git a/src/nb/analytics/memory_tracker.cc b/src/nb/analytics/memory_tracker.cc
index 8cb7664..56471dd 100644
--- a/src/nb/analytics/memory_tracker.cc
+++ b/src/nb/analytics/memory_tracker.cc
@@ -31,11 +31,37 @@
return t;
}
+
+MemoryStats GetProcessMemoryStats() {
+ MemoryStats memory_stats;
+
+ memory_stats.total_cpu_memory = SbSystemGetTotalCPUMemory();
+ memory_stats.used_cpu_memory = SbSystemGetUsedCPUMemory();
+
+ if (SbSystemHasCapability(kSbSystemCapabilityCanQueryGPUMemoryStats)) {
+ int64_t used_gpu_memory = SbSystemGetUsedGPUMemory();
+ memory_stats.total_gpu_memory = SbSystemGetTotalGPUMemory();
+ memory_stats.used_gpu_memory = SbSystemGetUsedGPUMemory();
+ }
+ return memory_stats;
+}
+
nb::scoped_ptr<MemoryTrackerPrintThread>
CreateDebugPrintThread(MemoryTracker* memory_tracker) {
return nb::scoped_ptr<MemoryTrackerPrintThread>(
new MemoryTrackerPrintThread(memory_tracker));
}
+nb::scoped_ptr<MemoryTrackerPrintCSVThread>
+CreateDebugPrintCSVThread(MemoryTracker* memory_tracker,
+ int sample_interval_ms,
+ int total_sampling_time_ms) {
+ return nb::scoped_ptr<MemoryTrackerPrintCSVThread>(
+ new MemoryTrackerPrintCSVThread(
+ memory_tracker,
+ sample_interval_ms,
+ total_sampling_time_ms));
+}
+
} // namespace analytics
} // namespace nb
diff --git a/src/nb/analytics/memory_tracker.h b/src/nb/analytics/memory_tracker.h
index 4884c89..7d1c332 100644
--- a/src/nb/analytics/memory_tracker.h
+++ b/src/nb/analytics/memory_tracker.h
@@ -28,10 +28,22 @@
class MemoryTracker;
class MemoryTrackerPrintThread;
+class MemoryTrackerPrintCSVThread;
class AllocationVisitor;
class AllocationGroup;
class AllocationRecord;
+struct MemoryStats {
+ 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;
+ int64_t used_gpu_memory;
+};
+
+MemoryStats GetProcessMemoryStats();
+
// Creates a MemoryTracker instance that implements the
// MemoryTracker. Once the instance is created it can begin tracking
// system allocations by calling InstallGlobalTrackingHooks().
@@ -142,6 +154,15 @@
scoped_ptr<MemoryTrackerPrintThread>
CreateDebugPrintThread(MemoryTracker* memory_tracker);
+// Creates a SimpleThread that will output the state of the memory
+// periodically. Start()/Cancel()/Join() are called AUTOMATICALLY with
+// this object. Start() is on the returned thread before it is returned.
+// Join() is automatically called on destruction.
+scoped_ptr<MemoryTrackerPrintCSVThread>
+ CreateDebugPrintCSVThread(MemoryTracker* memory_tracker,
+ int sample_interval_ms,
+ int total_sampling_time_ms);
+
} // namespace analytics
} // namespace nb
diff --git a/src/nb/analytics/memory_tracker_impl.cc b/src/nb/analytics/memory_tracker_impl.cc
index 3a9bdf4..a4a8c89 100644
--- a/src/nb/analytics/memory_tracker_impl.cc
+++ b/src/nb/analytics/memory_tracker_impl.cc
@@ -16,15 +16,66 @@
#include "nb/analytics/memory_tracker_impl.h"
+#include <cstring>
#include <iomanip>
+#include <iterator>
#include <sstream>
#include "nb/atomic.h"
-#include "starboard/log.h"
#include "starboard/atomic.h"
+#include "starboard/log.h"
+#include "starboard/time.h"
namespace nb {
namespace analytics {
+namespace {
+// NoMemoryTracking will disable memory tracking while in the current scope of
+// execution. When the object is destroyed it will reset the previous state
+// of allocation tracking.
+// Example:
+// void Foo() {
+// NoMemoryTracking no_memory_tracking_in_scope;
+// int* ptr = new int(); // ptr is not tracked.
+// delete ptr;
+// return; // Previous memory tracking state is restored.
+// }
+class NoMemoryTracking {
+ public:
+ NoMemoryTracking(MemoryTracker* owner) : owner_(owner) {
+ prev_val_ = owner_->IsMemoryTrackingEnabled();
+ owner_->SetMemoryTrackingEnabled(false);
+ }
+ ~NoMemoryTracking() { owner_->SetMemoryTrackingEnabled(prev_val_); }
+
+ private:
+ bool prev_val_;
+ MemoryTracker* owner_;
+};
+
+// This is a simple algorithm to remove the "needle" from the haystack. Note
+// that this function is simple and not well optimized.
+std::string RemoveString(const std::string& haystack, const char* needle) {
+ const size_t NOT_FOUND = std::string::npos;
+
+ // Base case. No modification needed.
+ size_t pos = haystack.find(needle);
+ if (pos == NOT_FOUND) {
+ return haystack;
+ }
+ const size_t n = strlen(needle);
+ std::string output;
+ output.reserve(haystack.size());
+
+ // Copy string, omitting the portion containing the "needle".
+ std::copy(haystack.begin(), haystack.begin() + pos,
+ std::back_inserter(output));
+ std::copy(haystack.begin() + pos + n, haystack.end(),
+ std::back_inserter(output));
+
+ // Recursively remove same needle in haystack.
+ return RemoveString(output, needle);
+}
+} // namespace
SbMemoryReporter* MemoryTrackerImpl::GetMemoryReporter() {
return &sb_memory_tracker_;
@@ -197,7 +248,7 @@
// We might do something more interesting with UnMapMemory calls later.
OnDealloc(context, memory);
}
-
+
void MemoryTrackerImpl::OnPushAllocationGroup(
void* context,
NbMemoryScopeInfo* memory_scope_info) {
@@ -346,15 +397,15 @@
prev_group_name = "none";
}
- if (!added) {
- std::stringstream ss;
- ss << "\nUnexpected condition, previous allocation was not removed:\n"
- << "\tprevious alloc group: " << prev_group_name << "\n"
- << "\tnew alloc group: " << group->name() << "\n"
- << "\tprevious size: " << unexpected_alloc.size << "\n"
- << "\tnew size: " << size << "\n";
-
- SbLogRaw(ss.str().c_str());
+ if (!added) {
+ std::stringstream ss;
+ ss << "\nUnexpected condition, previous allocation was not removed:\n"
+ << "\tprevious alloc group: " << prev_group_name << "\n"
+ << "\tnew alloc group: " << group->name() << "\n"
+ << "\tprevious size: " << unexpected_alloc.size << "\n"
+ << "\tnew size: " << size << "\n";
+
+ SbLogRaw(ss.str().c_str());
}
}
return added;
@@ -448,19 +499,8 @@
}
void MemoryTrackerPrintThread::Run() {
- struct NoMemTracking {
- NoMemTracking(MemoryTracker* owner) : owner_(owner) {
- prev_val_ = owner_->IsMemoryTrackingEnabled();
- owner_->SetMemoryTrackingEnabled(false);
- }
- ~NoMemTracking() { owner_->SetMemoryTrackingEnabled(prev_val_); }
-
- bool prev_val_;
- MemoryTracker* owner_;
- };
-
while (!finished_.load()) {
- NoMemTracking no_mem_tracking_in_this_scope(memory_tracker_);
+ NoMemoryTracking no_mem_tracking_in_this_scope(memory_tracker_);
// std::map<std::string, const AllocationGroup*> output;
// typedef std::map<std::string, const AllocationGroup*>::const_iterator
@@ -539,5 +579,258 @@
}
}
+MemoryTrackerPrintCSVThread::MemoryTrackerPrintCSVThread(
+ MemoryTracker* memory_tracker,
+ int sampling_interval_ms,
+ int sampling_time_ms)
+ : SimpleThread("MemoryTrackerPrintCSVThread"),
+ memory_tracker_(memory_tracker),
+ sample_interval_ms_(sampling_interval_ms),
+ sampling_time_ms_(sampling_time_ms),
+ start_time_(SbTimeGetNow()) {
+ Start();
+}
+
+
+MemoryTrackerPrintCSVThread::~MemoryTrackerPrintCSVThread() {
+ Cancel();
+ Join();
+}
+
+void MemoryTrackerPrintCSVThread::Cancel() {
+ canceled_.store(true);
+}
+
+std::string MemoryTrackerPrintCSVThread::ToCsvString(
+ const MapAllocationSamples& samples_in) {
+ typedef MapAllocationSamples Map;
+ typedef Map::const_iterator MapIt;
+
+ const char QUOTE[] = "\"";
+ const char DELIM[] = ",";
+ const char NEW_LINE[] = "\n";
+
+ size_t largest_sample_size = 0;
+ size_t smallest_sample_size = INT_MAX;
+
+ // Sanitize samples_in and store as samples.
+ MapAllocationSamples samples;
+ for (MapIt it = samples_in.begin(); it != samples_in.end(); ++it) {
+ std::string name = it->first;
+ const AllocationSamples& value = it->second;
+
+ if (value.allocated_bytes_.size() != value.number_allocations_.size()) {
+ SB_NOTREACHED() << "Error at " << __FILE__ << ":" << __LINE__;
+ return "ERROR";
+ }
+
+ const size_t n = value.allocated_bytes_.size();
+ if (n > largest_sample_size) {
+ largest_sample_size = n;
+ }
+ if (n < smallest_sample_size) {
+ smallest_sample_size = n;
+ }
+
+ // Strip out any characters that could make parsing the csv difficult.
+ name = RemoveString(name, QUOTE);
+ name = RemoveString(name, DELIM);
+ name = RemoveString(name, NEW_LINE);
+
+ const bool duplicate_found = (samples.end() != samples.find(name));
+ if (duplicate_found) {
+ SB_NOTREACHED() << "Error, duplicate found for entry: "
+ << name << NEW_LINE;
+ }
+ // Store value as a sanitized sample.
+ samples[name] = value;
+ }
+
+ SB_DCHECK(largest_sample_size == smallest_sample_size);
+
+ std::stringstream ss;
+
+ // Begin output to CSV.
+ // Sometimes we need to skip the CPU memory entry.
+ const MapIt total_cpu_memory_it = samples.find(UntrackedMemoryKey());
+
+ // Preamble
+ ss << NEW_LINE << "//////////////////////////////////////////////";
+ ss << NEW_LINE << "// CSV of bytes / allocation" << NEW_LINE;
+ // HEADER.
+ ss << "Name" << DELIM << QUOTE << "Bytes/Alloc" << QUOTE << NEW_LINE;
+ // DATA.
+ for (MapIt it = samples.begin(); it != samples.end(); ++it) {
+ if (total_cpu_memory_it == it) {
+ continue;
+ }
+
+ const AllocationSamples& samples = it->second;
+ if (samples.allocated_bytes_.empty() ||
+ samples.number_allocations_.empty()) {
+ SB_NOTREACHED() << "Should not be here";
+ return "ERROR";
+ }
+ const int32_t n_allocs = samples.number_allocations_.back();
+ const int64_t n_bytes = samples.allocated_bytes_.back();
+ int bytes_per_alloc = 0;
+ if (n_allocs > 0) {
+ bytes_per_alloc = n_bytes / n_allocs;
+ }
+ const std::string& name = it->first;
+ ss << QUOTE << name << QUOTE << DELIM << bytes_per_alloc << NEW_LINE;
+ }
+ ss << NEW_LINE;
+
+ // Preamble
+ ss << NEW_LINE << "//////////////////////////////////////////////"
+ << NEW_LINE << "// CSV of bytes allocated per region (MB's)."
+ << NEW_LINE << "// Units are in Megabytes. This is designed"
+ << NEW_LINE << "// to be used in a stacked graph." << NEW_LINE;
+
+ // HEADER.
+ for (MapIt it = samples.begin(); it != samples.end(); ++it) {
+ if (total_cpu_memory_it == it) {
+ continue;
+ }
+ const std::string& name = it->first;
+ ss << QUOTE << name << QUOTE << DELIM;
+ }
+ // Save the total for last.
+ if (total_cpu_memory_it != samples.end()) {
+ const std::string& name = total_cpu_memory_it->first;
+ ss << QUOTE << name << QUOTE << DELIM;
+ }
+ ss << NEW_LINE;
+
+ // Print out the values of each of the samples.
+ for (int i = 0; i < smallest_sample_size; ++i) {
+ for (MapIt it = samples.begin(); it != samples.end(); ++it) {
+ if (total_cpu_memory_it == it) {
+ continue;
+ }
+ const int64_t alloc_bytes = it->second.allocated_bytes_[i];
+ // Convert to float megabytes with decimals of precision.
+ double n = alloc_bytes / (1000 * 10);
+ n = n / (100.);
+ ss << n << DELIM;
+ }
+ if (total_cpu_memory_it != samples.end()) {
+ const int64_t alloc_bytes =
+ total_cpu_memory_it->second.allocated_bytes_[i];
+ // Convert to float megabytes with decimals of precision.
+ double n = alloc_bytes / (1000 * 10);
+ n = n / (100.);
+ ss << n << DELIM;
+ }
+ ss << NEW_LINE;
+ }
+
+ ss << NEW_LINE;
+ // Preamble
+ ss << NEW_LINE << "//////////////////////////////////////////////";
+ ss << NEW_LINE << "// CSV of number of allocations per region." << NEW_LINE;
+
+ // HEADER
+ for (MapIt it = samples.begin(); it != samples.end(); ++it) {
+ if (total_cpu_memory_it == it) {
+ continue;
+ }
+ const std::string& name = it->first;
+ ss << QUOTE << name << QUOTE << DELIM;
+ }
+ ss << NEW_LINE;
+ for (int i = 0; i < smallest_sample_size; ++i) {
+ for (MapIt it = samples.begin(); it != samples.end(); ++it) {
+ if (total_cpu_memory_it == it) {
+ continue;
+ }
+ const int64_t n_allocs = it->second.number_allocations_[i];
+ ss << n_allocs << DELIM;
+ }
+ ss << NEW_LINE;
+ }
+ std::string output = ss.str();
+ return output;
+}
+
+const char* MemoryTrackerPrintCSVThread::UntrackedMemoryKey() {
+ return "Untracked Memory";
+}
+
+void MemoryTrackerPrintCSVThread::Run() {
+ NoMemoryTracking no_mem_tracking_in_this_scope(memory_tracker_);
+
+ SbLogRaw("\nMemoryTrackerPrintCSVThread is sampling...\n");
+ int sample_count = 0;
+ MapAllocationSamples map_samples;
+
+ while (!TimeExpiredYet() && !canceled_.load()) {
+ // Sample total memory used by the system.
+ MemoryStats mem_stats = GetProcessMemoryStats();
+ int64_t untracked_used_memory = mem_stats.used_cpu_memory +
+ mem_stats.used_gpu_memory;
+
+ std::vector<const AllocationGroup*> vector_output;
+ memory_tracker_->GetAllocationGroups(&vector_output);
+
+ // Sample all known memory scopes.
+ for (int i = 0; i < vector_output.size(); ++i) {
+ const AllocationGroup* group = vector_output[i];
+ const std::string& name = group->name();
+
+ const bool first_creation = map_samples.find(group->name()) ==
+ map_samples.end();
+
+ AllocationSamples* new_entry = &(map_samples[name]);
+
+ // Didn't see it before so create new entry.
+ if (first_creation) {
+ // Make up for lost samples...
+ new_entry->allocated_bytes_.resize(sample_count, 0);
+ new_entry->number_allocations_.resize(sample_count, 0);
+ }
+
+ int32_t num_allocs = - 1;
+ int64_t allocation_bytes = -1;
+ group->GetAggregateStats(&num_allocs, &allocation_bytes);
+
+ new_entry->allocated_bytes_.push_back(allocation_bytes);
+ new_entry->number_allocations_.push_back(num_allocs);
+
+ untracked_used_memory -= allocation_bytes;
+ }
+
+ // Now push in remaining total.
+ AllocationSamples* process_sample = &(map_samples[UntrackedMemoryKey()]);
+ if (untracked_used_memory < 0) {
+ // On some platforms, total GPU memory may not be correctly reported.
+ // However the allocations from the GPU memory may be reported. In this
+ // case untracked_used_memory will go negative. To protect the memory
+ // reporting the untracked_used_memory is set to 0 so that it doesn't
+ // cause an error in reporting.
+ untracked_used_memory = 0;
+ }
+ process_sample->allocated_bytes_.push_back(untracked_used_memory);
+ process_sample->number_allocations_.push_back(-1);
+
+ ++sample_count;
+ SbThreadSleep(kSbTimeMillisecond * sample_interval_ms_);
+ }
+
+ std::string output = ToCsvString(map_samples);
+ SbLogRaw(output.c_str());
+ SbLogFlush();
+ // Prevents the "thread exited code 0" from being interleaved into the
+ // output. This happens if SbLogFlush() is not implemented for the platform.
+ SbThreadSleep(1000 * kSbTimeMillisecond);
+}
+
+bool MemoryTrackerPrintCSVThread::TimeExpiredYet() {
+ const SbTime diff_us = SbTimeGetNow() - start_time_;
+ const bool expired_time = diff_us > (sampling_time_ms_ * kSbTimeMillisecond);
+ return expired_time;
+}
+
} // namespace analytics
} // namespace nb
diff --git a/src/nb/analytics/memory_tracker_impl.h b/src/nb/analytics/memory_tracker_impl.h
index 1575e7b..1af04aa 100644
--- a/src/nb/analytics/memory_tracker_impl.h
+++ b/src/nb/analytics/memory_tracker_impl.h
@@ -26,6 +26,7 @@
#include "starboard/memory_reporter.h"
#include "starboard/memory.h"
#include "starboard/mutex.h"
+#include "starboard/time.h"
namespace nb {
namespace analytics {
@@ -177,7 +178,7 @@
// Start() is called when this object is created, and Cancel() & Join() are
// called during destruction.
-class MemoryTrackerPrintThread : private SimpleThread {
+class MemoryTrackerPrintThread : public SimpleThread {
public:
MemoryTrackerPrintThread(MemoryTracker* memory_tracker);
virtual ~MemoryTrackerPrintThread() SB_OVERRIDE;
@@ -191,6 +192,41 @@
MemoryTracker* memory_tracker_;
};
+// Generates CSV values of the engine.
+// There are three sections of data including:
+// 1. average bytes / alloc
+// 2. # Bytes allocated per memory scope.
+// 3. # Allocations per memory scope.
+// This data can be pasted directly into a Google spreadsheet and visualized.
+// Note that this thread will implicitly call Start() is called during
+// construction and Cancel() & Join() during destruction.
+class MemoryTrackerPrintCSVThread : public SimpleThread {
+ public:
+ MemoryTrackerPrintCSVThread(MemoryTracker* memory_tracker,
+ int sampling_interval_ms,
+ int sampling_time_ms);
+ virtual ~MemoryTrackerPrintCSVThread() SB_OVERRIDE;
+
+ // Overridden so that the thread can exit gracefully.
+ virtual void Cancel() SB_OVERRIDE;
+ virtual void Run() SB_OVERRIDE;
+ private:
+ struct AllocationSamples {
+ std::vector<int32_t> number_allocations_;
+ std::vector<int64_t> allocated_bytes_;
+ };
+ typedef std::map<std::string, AllocationSamples> MapAllocationSamples;
+ static std::string ToCsvString(const MapAllocationSamples& samples);
+ static const char* UntrackedMemoryKey();
+ bool TimeExpiredYet();
+
+ MemoryTracker* memory_tracker_;
+ const int sample_interval_ms_;
+ const int sampling_time_ms_;
+ SbTime start_time_;
+ atomic_bool canceled_;
+};
+
} // namespace analytics
} // namespace nb
diff --git a/src/nb/memory_scope.h b/src/nb/memory_scope.h
index d7d37bf..72e1ddc 100644
--- a/src/nb/memory_scope.h
+++ b/src/nb/memory_scope.h
@@ -124,7 +124,7 @@
// When true, if cached_handle_ is 0 then an object may be created that
// represents the fields of this object. The handle that represents this
// cached object is then placed in cached_hanlde_.
- const bool allows_caching_;
+ bool allows_caching_;
};
// NbPopMemoryScopeOnScopeEnd is only allowed for C++ builds.
diff --git a/src/net/base/data_url.cc b/src/net/base/data_url.cc
index b7309cb..53a5ea8 100644
--- a/src/net/base/data_url.cc
+++ b/src/net/base/data_url.cc
@@ -13,6 +13,7 @@
#include "base/string_split.h"
#include "base/string_util.h"
#include "googleurl/src/gurl.h"
+#include "nb/memory_scope.h"
#include "net/base/escape.h"
namespace net {
@@ -20,6 +21,7 @@
// static
bool DataURL::Parse(const GURL& url, std::string* mime_type,
std::string* charset, std::string* data) {
+ TRACK_MEMORY_SCOPE("Network");
DCHECK(mime_type->empty());
DCHECK(charset->empty());
std::string::const_iterator begin = url.spec().begin();
diff --git a/src/net/base/host_resolver_impl.cc b/src/net/base/host_resolver_impl.cc
index 11ccd9f..9c1ac57 100644
--- a/src/net/base/host_resolver_impl.cc
+++ b/src/net/base/host_resolver_impl.cc
@@ -44,6 +44,7 @@
#include "net/dns/dns_protocol.h"
#include "net/dns/dns_response.h"
#include "net/dns/dns_transaction.h"
+#include "nb/memory_scope.h"
#if defined(OS_WIN)
#include "net/base/winsock_init.h"
@@ -580,6 +581,7 @@
~ProcTask() {}
void StartLookupAttempt() {
+ TRACK_MEMORY_SCOPE("Network");
DCHECK(origin_loop_->BelongsToCurrentThread());
base::TimeTicks start_time = base::TimeTicks::Now();
++attempt_number_;
diff --git a/src/net/base/host_resolver_proc.cc b/src/net/base/host_resolver_proc.cc
index 8950f5b..a4512e9 100644
--- a/src/net/base/host_resolver_proc.cc
+++ b/src/net/base/host_resolver_proc.cc
@@ -12,6 +12,7 @@
#include "net/base/dns_reloader.h"
#include "net/base/net_errors.h"
#include "net/base/sys_addrinfo.h"
+#include "nb/memory_scope.h"
#if defined(OS_STARBOARD)
#include "starboard/socket.h"
@@ -133,6 +134,7 @@
HostResolverFlags host_resolver_flags,
AddressList* addrlist,
int* os_error) {
+ TRACK_MEMORY_SCOPE("Network");
if (os_error)
*os_error = 0;
diff --git a/src/net/base/net_errors.h b/src/net/base/net_errors.h
index 95a81e9..43cffab 100644
--- a/src/net/base/net_errors.h
+++ b/src/net/base/net_errors.h
@@ -49,7 +49,7 @@
NET_EXPORT Error MapSocketError(SbSocketError error);
// Gets the last socket error as a net error.
-SB_C_INLINE Error MapLastSocketError(SbSocket socket) {
+static SB_C_INLINE Error MapLastSocketError(SbSocket socket) {
return MapSocketError(SbSocketGetLastError(socket));
}
@@ -57,7 +57,7 @@
NET_EXPORT Error MapSystemError(SbSystemError error);
// Gets the last system error as a net error.
-SB_C_INLINE Error MapLastSystemError() {
+static SB_C_INLINE Error MapLastSystemError() {
return MapSystemError(SbSystemGetLastError());
}
diff --git a/src/net/http/http_stream_factory_impl_job.cc b/src/net/http/http_stream_factory_impl_job.cc
index 77422ce..9554ce6 100644
--- a/src/net/http/http_stream_factory_impl_job.cc
+++ b/src/net/http/http_stream_factory_impl_job.cc
@@ -12,6 +12,7 @@
#include "base/stringprintf.h"
#include "base/values.h"
#include "build/build_config.h"
+#include "nb/memory_scope.h"
#include "net/base/connection_type_histograms.h"
#include "net/base/net_log.h"
#include "net/base/net_util.h"
@@ -267,6 +268,7 @@
}
void HttpStreamFactoryImpl::Job::OnStreamReadyCallback() {
+ TRACK_MEMORY_SCOPE("Network");
DCHECK(stream_.get());
DCHECK(!IsPreconnecting());
if (IsOrphaned()) {
diff --git a/src/net/net.gyp b/src/net/net.gyp
index 3d7b9d4..d13a159 100644
--- a/src/net/net.gyp
+++ b/src/net/net.gyp
@@ -57,6 +57,7 @@
'../base/third_party/dynamic_annotations/dynamic_annotations.gyp:dynamic_annotations',
'../googleurl/googleurl.gyp:googleurl',
'../crypto/crypto.gyp:crypto',
+ '../nb/nb.gyp:nb',
'../third_party/icu/icu.gyp:icui18n',
'../third_party/icu/icu.gyp:icuuc',
'../third_party/zlib/zlib.gyp:zlib',
diff --git a/src/net/socket/client_socket_handle.cc b/src/net/socket/client_socket_handle.cc
index 20ab672..cffb902 100644
--- a/src/net/socket/client_socket_handle.cc
+++ b/src/net/socket/client_socket_handle.cc
@@ -9,6 +9,7 @@
#include "base/compiler_specific.h"
#include "base/metrics/histogram.h"
#include "base/logging.h"
+#include "nb/memory_scope.h"
#include "net/base/net_errors.h"
#include "net/socket/client_socket_pool.h"
#include "net/socket/client_socket_pool_histograms.h"
@@ -104,6 +105,7 @@
}
void ClientSocketHandle::OnIOComplete(int result) {
+ TRACK_MEMORY_SCOPE("Network");
CompletionCallback callback = user_callback_;
user_callback_.Reset();
HandleInitCompletion(result);
@@ -111,6 +113,7 @@
}
void ClientSocketHandle::HandleInitCompletion(int result) {
+ TRACK_MEMORY_SCOPE("Network");
CHECK_NE(ERR_IO_PENDING, result);
if (result != OK) {
if (!socket_.get())
diff --git a/src/net/socket/tcp_client_socket_starboard.cc b/src/net/socket/tcp_client_socket_starboard.cc
index 48d76b5..c970ac7 100644
--- a/src/net/socket/tcp_client_socket_starboard.cc
+++ b/src/net/socket/tcp_client_socket_starboard.cc
@@ -23,6 +23,7 @@
#include "base/posix/eintr_wrapper.h"
#include "base/string_util.h"
#include "base/stringprintf.h"
+#include "nb/memory_scope.h"
#include "net/base/address_family.h"
#include "net/base/connection_type_histograms.h"
#include "net/base/io_buffer.h"
@@ -154,6 +155,7 @@
}
int TCPClientSocketStarboard::Connect(const CompletionCallback& callback) {
+ TRACK_MEMORY_SCOPE("Network");
DCHECK(CalledOnValidThread());
// If this socket is already valid, then just return OK.
@@ -186,6 +188,7 @@
// pretty much cribbed directly from TCPClientSocketLibevent and/or
// TCPClientSocketWin, take your pick, they're identical
int TCPClientSocketStarboard::DoConnectLoop(int result) {
+ TRACK_MEMORY_SCOPE("Network");
DCHECK_NE(next_connect_state_, CONNECT_STATE_NONE);
int rv = result;
@@ -211,6 +214,7 @@
}
int TCPClientSocketStarboard::DoConnect() {
+ TRACK_MEMORY_SCOPE("Network");
DCHECK_GE(current_address_index_, 0);
DCHECK_LT(current_address_index_, static_cast<int>(addresses_.size()));
@@ -257,6 +261,7 @@
}
int TCPClientSocketStarboard::DoConnectComplete(int result) {
+ TRACK_MEMORY_SCOPE("Network");
// Log the end of this attempt (and any OS error it threw).
int error = connect_error_;
connect_error_ = OK;
@@ -287,6 +292,7 @@
}
void TCPClientSocketStarboard::DidCompleteConnect() {
+ TRACK_MEMORY_SCOPE("Network");
DCHECK_EQ(next_connect_state_, CONNECT_STATE_CONNECT_COMPLETE);
connect_error_ = SbSocketIsConnected(socket_) ? OK : ERR_FAILED;
@@ -298,6 +304,7 @@
}
void TCPClientSocketStarboard::LogConnectCompletion(int net_error) {
+ TRACK_MEMORY_SCOPE("Network");
if (net_error == OK)
UpdateConnectionTypeHistograms(CONNECTION_ANY);
@@ -422,6 +429,7 @@
int TCPClientSocketStarboard::Read(IOBuffer* buf,
int buf_len,
const CompletionCallback& callback) {
+ TRACK_MEMORY_SCOPE("Network");
DCHECK(SbSocketIsValid(socket_));
DCHECK(!waiting_connect());
DCHECK(!waiting_read_);
@@ -459,6 +467,7 @@
}
void TCPClientSocketStarboard::DidCompleteRead() {
+ TRACK_MEMORY_SCOPE("Network");
DCHECK(waiting_read_);
int bytes_read =
SbSocketReceiveFrom(socket_, read_buf_->data(), read_buf_len_, NULL);
@@ -485,6 +494,7 @@
}
void TCPClientSocketStarboard::DoReadCallback(int rv) {
+ TRACK_MEMORY_SCOPE("Network");
DCHECK_NE(rv, ERR_IO_PENDING);
// since Run may result in Read being called, clear read_callback_ up front.
@@ -496,6 +506,7 @@
int TCPClientSocketStarboard::Write(IOBuffer* buf,
int buf_len,
const CompletionCallback& callback) {
+ TRACK_MEMORY_SCOPE("Network");
DCHECK(SbSocketIsValid(socket_));
DCHECK(!waiting_connect());
DCHECK(!waiting_write_);
@@ -535,6 +546,7 @@
}
void TCPClientSocketStarboard::DidCompleteWrite() {
+ TRACK_MEMORY_SCOPE("Network");
DCHECK(waiting_write_);
int nwrite =
SbSocketSendTo(socket_, write_buf_->data(), write_buf_len_, NULL);
@@ -560,6 +572,7 @@
}
void TCPClientSocketStarboard::DoWriteCallback(int rv) {
+ TRACK_MEMORY_SCOPE("Network");
DCHECK_NE(rv, ERR_IO_PENDING);
// since Run may result in Write being called, clear write_callback_ up front.
@@ -569,22 +582,27 @@
}
bool TCPClientSocketStarboard::SetReceiveBufferSize(int32 size) {
+ TRACK_MEMORY_SCOPE("Network");
return SbSocketSetReceiveBufferSize(socket_, size);
}
bool TCPClientSocketStarboard::SetSendBufferSize(int32 size) {
+ TRACK_MEMORY_SCOPE("Network");
return SbSocketSetSendBufferSize(socket_, size);
}
bool TCPClientSocketStarboard::SetKeepAlive(bool enable, int delay) {
+ TRACK_MEMORY_SCOPE("Network");
return SbSocketSetTcpKeepAlive(socket_, enable, delay);
}
bool TCPClientSocketStarboard::SetNoDelay(bool no_delay) {
+ TRACK_MEMORY_SCOPE("Network");
return SbSocketSetTcpNoDelay(socket_, no_delay);
}
bool TCPClientSocketStarboard::SetWindowScaling(bool enable) {
+ TRACK_MEMORY_SCOPE("Network");
return SbSocketSetTcpWindowScaling(socket_, enable);
}
diff --git a/src/net/udp/udp_listen_socket.cc b/src/net/udp/udp_listen_socket.cc
index 848290b..82fdfd9 100644
--- a/src/net/udp/udp_listen_socket.cc
+++ b/src/net/udp/udp_listen_socket.cc
@@ -33,6 +33,7 @@
#include "base/sys_byteorder.h"
#include "base/threading/platform_thread.h"
#include "build/build_config.h"
+#include "nb/memory_scope.h"
#include "net/base/net_util.h"
#if defined(OS_STARBOARD)
#include "starboard/socket.h"
@@ -87,12 +88,14 @@
void UDPListenSocket::SendTo(const IPEndPoint& address,
const std::string& str) {
+ TRACK_MEMORY_SCOPE("Network");
SendTo(address, str.data(), static_cast<int>(str.length()));
}
void UDPListenSocket::SendTo(const IPEndPoint& address,
const char* bytes,
int len) {
+ TRACK_MEMORY_SCOPE("Network");
#if defined(OS_STARBOARD)
SbSocketAddress dst_addr;
if (!address.ToSbSocketAddress(&dst_addr)) {
@@ -130,6 +133,7 @@
}
void UDPListenSocket::Read() {
+ TRACK_MEMORY_SCOPE("Network");
if (buffer_ == NULL) {
// +1 for null termination
buffer_.reset(new char[kUdpMaxPacketSize + 1]);
@@ -192,6 +196,7 @@
}
void UDPListenSocket::WatchSocket() {
+ TRACK_MEMORY_SCOPE("Network");
#if defined(OS_STARBOARD)
MessageLoopForIO::current()->Watch(
socket_, true, MessageLoopForIO::WATCH_READ, &watcher_, this);
diff --git a/src/net/url_request/url_fetcher_core.cc b/src/net/url_request/url_fetcher_core.cc
index ea36c74..82976da 100644
--- a/src/net/url_request/url_fetcher_core.cc
+++ b/src/net/url_request/url_fetcher_core.cc
@@ -13,6 +13,7 @@
#include "base/stl_util.h"
#include "base/thread_task_runner_handle.h"
#include "base/tracked_objects.h"
+#include "nb/memory_scope.h"
#include "net/base/io_buffer.h"
#include "net/base/load_flags.h"
#include "net/base/net_errors.h"
@@ -42,6 +43,7 @@
URLFetcherCore::Registry::~Registry() {}
void URLFetcherCore::Registry::AddURLFetcherCore(URLFetcherCore* core) {
+ TRACK_MEMORY_SCOPE("Network");
DCHECK(!ContainsKey(fetchers_, core));
fetchers_.insert(core);
}
@@ -75,6 +77,7 @@
void URLFetcherCore::FileWriter::CreateFileAtPath(
const FilePath& file_path) {
+ TRACK_MEMORY_SCOPE("Network");
DCHECK(core_->network_task_runner_->BelongsToCurrentThread());
DCHECK(file_task_runner_.get());
base::FileUtilProxy::CreateOrOpen(
@@ -87,6 +90,7 @@
}
void URLFetcherCore::FileWriter::CreateTempFile() {
+ TRACK_MEMORY_SCOPE("Network");
DCHECK(core_->network_task_runner_->BelongsToCurrentThread());
DCHECK(file_task_runner_.get());
base::FileUtilProxy::CreateTemporary(
@@ -97,6 +101,7 @@
}
void URLFetcherCore::FileWriter::WriteBuffer(int num_bytes) {
+ TRACK_MEMORY_SCOPE("Network");
DCHECK(core_->network_task_runner_->BelongsToCurrentThread());
// Start writing to the file by setting the initial state
@@ -110,6 +115,7 @@
void URLFetcherCore::FileWriter::ContinueWrite(
base::PlatformFileError error_code,
int bytes_written) {
+ TRACK_MEMORY_SCOPE("Network");
DCHECK(core_->network_task_runner_->BelongsToCurrentThread());
if (file_handle_ == base::kInvalidPlatformFileValue) {
@@ -154,6 +160,7 @@
}
void URLFetcherCore::FileWriter::DisownFile() {
+ TRACK_MEMORY_SCOPE("Network");
DCHECK(core_->network_task_runner_->BelongsToCurrentThread());
// Disowning is done by the delegate's OnURLFetchComplete method.
@@ -165,6 +172,7 @@
}
void URLFetcherCore::FileWriter::CloseFileAndCompleteRequest() {
+ TRACK_MEMORY_SCOPE("Network");
DCHECK(core_->network_task_runner_->BelongsToCurrentThread());
if (file_handle_ != base::kInvalidPlatformFileValue) {
@@ -177,6 +185,7 @@
}
void URLFetcherCore::FileWriter::CloseAndDeleteFile() {
+ TRACK_MEMORY_SCOPE("Network");
DCHECK(core_->network_task_runner_->BelongsToCurrentThread());
if (file_handle_ == base::kInvalidPlatformFileValue) {
@@ -193,6 +202,7 @@
void URLFetcherCore::FileWriter::DeleteFile(
base::PlatformFileError error_code) {
+ TRACK_MEMORY_SCOPE("Network");
DCHECK(core_->network_task_runner_->BelongsToCurrentThread());
if (file_path_.empty())
return;
@@ -209,6 +219,7 @@
base::PlatformFileError error_code,
base::PassPlatformFile file_handle,
bool created) {
+ TRACK_MEMORY_SCOPE("Network");
DidCreateFileInternal(file_path, error_code, file_handle);
}
@@ -216,6 +227,7 @@
base::PlatformFileError error_code,
base::PassPlatformFile file_handle,
const FilePath& file_path) {
+ TRACK_MEMORY_SCOPE("Network");
DidCreateFileInternal(file_path, error_code, file_handle);
}
@@ -223,6 +235,7 @@
const FilePath& file_path,
base::PlatformFileError error_code,
base::PassPlatformFile file_handle) {
+ TRACK_MEMORY_SCOPE("Network");
DCHECK(core_->network_task_runner_->BelongsToCurrentThread());
if (base::PLATFORM_FILE_OK != error_code) {
@@ -245,6 +258,7 @@
void URLFetcherCore::FileWriter::DidCloseFile(
base::PlatformFileError error_code) {
+ TRACK_MEMORY_SCOPE("Network");
DCHECK(core_->network_task_runner_->BelongsToCurrentThread());
if (base::PLATFORM_FILE_OK != error_code) {
@@ -300,6 +314,7 @@
}
void URLFetcherCore::Start() {
+ TRACK_MEMORY_SCOPE("Network");
DCHECK(delegate_task_runner_);
DCHECK(request_context_getter_) << "We need an URLRequestContext!";
if (network_task_runner_) {
@@ -315,6 +330,7 @@
}
void URLFetcherCore::Stop() {
+ TRACK_MEMORY_SCOPE("Network");
if (delegate_task_runner_) // May be NULL in tests.
DCHECK(delegate_task_runner_->BelongsToCurrentThread());
@@ -523,6 +539,7 @@
bool URLFetcherCore::GetResponseAsFilePath(bool take_ownership,
FilePath* out_response_path) {
+ TRACK_MEMORY_SCOPE("Network");
DCHECK(delegate_task_runner_->BelongsToCurrentThread());
const bool destination_is_file =
response_destination_ == URLFetcherCore::TEMP_FILE ||
@@ -543,6 +560,7 @@
void URLFetcherCore::OnReceivedRedirect(URLRequest* request,
const GURL& new_url,
bool* defer_redirect) {
+ TRACK_MEMORY_SCOPE("Network");
DCHECK_EQ(request, request_.get());
DCHECK(network_task_runner_->BelongsToCurrentThread());
if (stop_on_redirect_) {
@@ -556,6 +574,7 @@
}
void URLFetcherCore::OnResponseStarted(URLRequest* request) {
+ TRACK_MEMORY_SCOPE("Network");
DCHECK_EQ(request, request_.get());
DCHECK(network_task_runner_->BelongsToCurrentThread());
if (request_->status().is_success()) {
@@ -593,6 +612,7 @@
void URLFetcherCore::OnReadCompleted(URLRequest* request,
int bytes_read) {
+ TRACK_MEMORY_SCOPE("Network");
DCHECK(request == request_);
DCHECK(network_task_runner_->BelongsToCurrentThread());
#if !defined(COBALT)
@@ -714,6 +734,7 @@
}
void URLFetcherCore::StartURLRequest() {
+ TRACK_MEMORY_SCOPE("Network");
DCHECK(network_task_runner_->BelongsToCurrentThread());
TRACE_EVENT_ASYNC_STEP0("net::url_request", "URLFetcher", this,
"Waiting For Data");
@@ -808,6 +829,7 @@
}
void URLFetcherCore::StartURLRequestWhenAppropriate() {
+ TRACK_MEMORY_SCOPE("Network");
TRACE_EVENT_ASYNC_BEGIN1("net::url_request", "URLFetcher", this, "url",
original_url_.path());
DCHECK(network_task_runner_->BelongsToCurrentThread());
@@ -841,6 +863,7 @@
}
void URLFetcherCore::CancelURLRequest() {
+ TRACK_MEMORY_SCOPE("Network");
DCHECK(network_task_runner_->BelongsToCurrentThread());
if (request_.get()) {
@@ -862,6 +885,7 @@
void URLFetcherCore::OnCompletedURLRequest(
base::TimeDelta backoff_delay) {
+ TRACK_MEMORY_SCOPE("Network");
TRACE_EVENT_ASYNC_END1("net::url_request", "URLFetcher", this, "url",
original_url_.path());
DCHECK(delegate_task_runner_->BelongsToCurrentThread());
@@ -874,12 +898,14 @@
}
void URLFetcherCore::InformDelegateFetchIsComplete() {
+ TRACK_MEMORY_SCOPE("Network");
DCHECK(delegate_task_runner_->BelongsToCurrentThread());
if (delegate_)
delegate_->OnURLFetchComplete(fetcher_);
}
void URLFetcherCore::NotifyMalformedContent() {
+ TRACK_MEMORY_SCOPE("Network");
DCHECK(network_task_runner_->BelongsToCurrentThread());
if (url_throttler_entry_ != NULL) {
int status_code = response_code_;
@@ -896,6 +922,7 @@
}
void URLFetcherCore::RetryOrCompleteUrlFetch() {
+ TRACK_MEMORY_SCOPE("Network");
DCHECK(network_task_runner_->BelongsToCurrentThread());
base::TimeDelta backoff_delay;
@@ -965,6 +992,7 @@
}
base::TimeTicks URLFetcherCore::GetBackoffReleaseTime() {
+ TRACK_MEMORY_SCOPE("Network");
DCHECK(network_task_runner_->BelongsToCurrentThread());
if (original_url_throttler_entry_) {
@@ -986,6 +1014,7 @@
void URLFetcherCore::CompleteAddingUploadDataChunk(
const std::string& content, bool is_last_chunk) {
+ TRACK_MEMORY_SCOPE("Network");
if (was_cancelled_) {
// Since CompleteAddingUploadDataChunk() is posted as a *delayed* task, it
// may run after the URLFetcher was already stopped.
@@ -1003,6 +1032,7 @@
// Return false if the write is pending, and the next read will
// be done later.
bool URLFetcherCore::WriteBuffer(int num_bytes) {
+ TRACK_MEMORY_SCOPE("Network");
bool write_complete = false;
switch (response_destination_) {
case STRING:
@@ -1031,6 +1061,7 @@
}
void URLFetcherCore::ReadResponse() {
+ TRACK_MEMORY_SCOPE("Network");
// Some servers may treat HEAD requests as GET requests. To free up the
// network connection as soon as possible, signal that the request has
// completed immediately, without trying to read any data back (all we care
@@ -1069,6 +1100,7 @@
#endif // defined(COBALT)
void URLFetcherCore::InformDelegateUploadProgress() {
+ TRACK_MEMORY_SCOPE("Network");
DCHECK(network_task_runner_->BelongsToCurrentThread());
if (request_.get()) {
int64 current = request_->GetUploadProgress().position();
@@ -1088,12 +1120,14 @@
void URLFetcherCore::InformDelegateUploadProgressInDelegateThread(
int64 current, int64 total) {
+ TRACK_MEMORY_SCOPE("Network");
DCHECK(delegate_task_runner_->BelongsToCurrentThread());
if (delegate_)
delegate_->OnURLFetchUploadProgress(fetcher_, current, total);
}
void URLFetcherCore::InformDelegateDownloadDataIfNecessary(int bytes_read) {
+ TRACK_MEMORY_SCOPE("Network");
DCHECK(network_task_runner_->BelongsToCurrentThread());
if (delegate_ && delegate_->ShouldSendDownloadData() && bytes_read != 0) {
if (!download_data_cache_) {
@@ -1114,6 +1148,7 @@
}
void URLFetcherCore::InformDelegateDownloadData() {
+ TRACK_MEMORY_SCOPE("Network");
DCHECK(network_task_runner_->BelongsToCurrentThread());
if (delegate_ && delegate_->ShouldSendDownloadData() &&
download_data_cache_) {
@@ -1126,6 +1161,7 @@
void URLFetcherCore::InformDelegateDownloadDataInDelegateThread(
scoped_ptr<std::string> download_data) {
+ TRACK_MEMORY_SCOPE("Network");
DCHECK(delegate_task_runner_->BelongsToCurrentThread());
if (delegate_) {
delegate_->OnURLFetchDownloadData(fetcher_, download_data.Pass());
diff --git a/src/net/url_request/url_request_data_job.cc b/src/net/url_request/url_request_data_job.cc
index 5dffe32..e0c0cba 100644
--- a/src/net/url_request/url_request_data_job.cc
+++ b/src/net/url_request/url_request_data_job.cc
@@ -6,6 +6,7 @@
#include "net/url_request/url_request_data_job.h"
+#include "nb/memory_scope.h"
#include "net/base/data_url.h"
#include "net/base/net_errors.h"
@@ -27,6 +28,7 @@
std::string* charset,
std::string* data,
const CompletionCallback& callback) const {
+ TRACK_MEMORY_SCOPE("Network");
// Check if data URL is valid. If not, don't bother to try to extract data.
// Otherwise, parse the data from the data URL.
const GURL& url = request_->url();
diff --git a/src/starboard/build/convert_i18n_data.py b/src/starboard/build/convert_i18n_data.py
index a34916a..0f56a59 100644
--- a/src/starboard/build/convert_i18n_data.py
+++ b/src/starboard/build/convert_i18n_data.py
@@ -51,7 +51,7 @@
messages = root[0]
# Write each message to the output file on its own line.
- with open(output_filename, 'w') as output_file:
+ with open(output_filename, 'wb') as output_file:
for msg in messages:
# Use ; as the separator. Which means it better not be in the name.
assert not (';' in msg.attrib['name'])
diff --git a/src/starboard/client_porting/poem/getenv_stub_poem.h b/src/starboard/client_porting/poem/getenv_stub_poem.h
new file mode 100644
index 0000000..8e4ab81
--- /dev/null
+++ b/src/starboard/client_porting/poem/getenv_stub_poem.h
@@ -0,0 +1,28 @@
+// Copyright 2016 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+// A poem (POsix EMulation) stub implementation for getenv.
+
+#ifndef STARBOARD_CLIENT_PORTING_POEM_GETENV_STUB_POEM_H_
+#define STARBOARD_CLIENT_PORTING_POEM_GETENV_STUB_POEM_H_
+
+#include <stdlib.h>
+
+#include "starboard/configuration.h"
+
+static SB_C_INLINE const char* getenv(const char* unused) {
+ return NULL;
+}
+
+#endif // STARBOARD_CLIENT_PORTING_POEM_GETENV_STUB_POEM_H_
diff --git a/src/starboard/client_porting/poem/inet_poem.h b/src/starboard/client_porting/poem/inet_poem.h
new file mode 100644
index 0000000..55cf47a
--- /dev/null
+++ b/src/starboard/client_porting/poem/inet_poem.h
@@ -0,0 +1,27 @@
+// Copyright 2016 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+// A poem (POsix EMulation) for functions usually declared in <arpa/inet.h>
+
+#ifndef STARBOARD_CLIENT_PORTING_POEM_INET_POEM_H_
+#define STARBOARD_CLIENT_PORTING_POEM_INET_POEM_H_
+
+#include "starboard/byte_swap.h"
+
+#define htonl(x) SB_HOST_TO_NET_U32(x)
+#define htons(x) SB_HOST_TO_NET_U16(x)
+#define ntohl(x) SB_NET_TO_HOST_U32(x)
+#define ntohs(x) SB_NET_TO_HOST_U16(x)
+
+#endif // STARBOARD_CLIENT_PORTING_POEM_INET_POEM_H_
diff --git a/src/starboard/client_porting/poem/poem.gyp b/src/starboard/client_porting/poem/poem.gyp
index def3f4e..947cc36 100644
--- a/src/starboard/client_porting/poem/poem.gyp
+++ b/src/starboard/client_porting/poem/poem.gyp
@@ -19,10 +19,13 @@
'type': 'static_library',
'sources': [
'eztime_poem.h',
+ 'getenv_stub_poem.h',
+ 'inet_poem.h',
'stdio_poem.h',
'stdlib_poem.h',
'string_poem.h',
'strings_poem.h',
+ 'strnlen_poem.h',
'wchar_poem.h',
],
'dependencies': [
@@ -44,5 +47,16 @@
'<(DEPTH)/starboard/starboard.gyp:starboard',
],
},
+ {
+ 'target_name': 'poem_unittests_deploy',
+ 'type': 'none',
+ 'dependencies': [
+ 'poem_unittests',
+ ],
+ 'variables': {
+ 'executable_name': 'poem_unittests',
+ },
+ 'includes': [ '../../build/deploy.gypi' ],
+ },
],
}
diff --git a/src/starboard/client_porting/poem/string_poem_test.cc b/src/starboard/client_porting/poem/string_poem_test.cc
index 2243b48..1a3e899 100644
--- a/src/starboard/client_porting/poem/string_poem_test.cc
+++ b/src/starboard/client_porting/poem/string_poem_test.cc
@@ -17,6 +17,7 @@
#include "testing/gtest/include/gtest/gtest.h"
#include "starboard/client_porting/poem/string_poem.h"
+#include "starboard/client_porting/poem/strnlen_poem.h"
namespace starboard {
namespace nplb {
@@ -76,6 +77,20 @@
EXPECT_STREQ(a, "Wu");
}
+TEST(StringPoemTest, PoemStringGetLengthFixed) {
+ char a[] = "abcdef";
+ char b[] = "abc\0def";
+
+ EXPECT_EQ(strnlen(a, 0), 0);
+ EXPECT_EQ(strnlen(a, 3), 3);
+ EXPECT_EQ(strnlen(a, sizeof(a)), 6);
+ EXPECT_EQ(strnlen(a, 256), 6);
+ EXPECT_EQ(strnlen(b, 2), 2);
+ EXPECT_EQ(strnlen(b, 3), 3);
+ EXPECT_EQ(strnlen(b, sizeof(b)), 3);
+ EXPECT_EQ(strnlen(b, 256), 3);
+}
+
} // namespace
} // namespace nplb
} // namespace starboard
diff --git a/src/starboard/client_porting/poem/strnlen_poem.h b/src/starboard/client_porting/poem/strnlen_poem.h
new file mode 100644
index 0000000..fb2d674
--- /dev/null
+++ b/src/starboard/client_porting/poem/strnlen_poem.h
@@ -0,0 +1,33 @@
+// Copyright 2016 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+// A poem (POsix EMulation) implementation for strnlen. Usually declared in
+// <string.h>, but may be missing on some platforms (e.g. PS3).
+
+#ifndef STARBOARD_CLIENT_PORTING_POEM_STRNLEN_POEM_H_
+#define STARBOARD_CLIENT_PORTING_POEM_STRNLEN_POEM_H_
+
+#include "starboard/configuration.h"
+
+static SB_C_INLINE size_t StringGetLengthFixed(const char* s, size_t maxlen) {
+ size_t i = 0;
+ while (i < maxlen && s[i]) {
+ ++i;
+ }
+ return i;
+}
+
+#define strnlen(s, maxlen) StringGetLengthFixed(s, maxlen)
+
+#endif // STARBOARD_CLIENT_PORTING_POEM_STRNLEN_POEM_H_
diff --git a/src/starboard/client_porting/pr_starboard/pr_starboard.cc b/src/starboard/client_porting/pr_starboard/pr_starboard.cc
new file mode 100644
index 0000000..732ea14
--- /dev/null
+++ b/src/starboard/client_porting/pr_starboard/pr_starboard.cc
@@ -0,0 +1,281 @@
+// Copyright 2016 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "starboard/client_porting/pr_starboard/pr_starboard.h"
+
+#include "starboard/condition_variable.h"
+#include "starboard/log.h"
+#include "starboard/memory.h"
+#include "starboard/mutex.h"
+#include "starboard/once.h"
+#include "starboard/queue.h"
+#include "starboard/thread.h"
+#include "starboard/time.h"
+#include "starboard/types.h"
+
+namespace {
+
+typedef starboard::Queue<bool> SetupSignalQueue;
+
+// Utility function to convert a PRInterval to signed 64 bit integer
+// microseconds.
+int64_t PR_IntervalToMicrosecondsInt64(PRIntervalTime ticks) {
+ uint32_t microseconds_as_uint32 = PR_IntervalToMicroseconds(ticks);
+ int64_t microseconds_as_int64 = static_cast<int64_t>(microseconds_as_uint32);
+ return microseconds_as_int64;
+}
+
+// Struct to bundle up arguments to be passed into SbThreadCreate.
+struct ThreadEntryPointWrapperContext {
+ ThreadEntryPointWrapperContext(void* pr_context,
+ PRThread* pr_thread,
+ PRThreadEntryPoint pr_entry_point,
+ SetupSignalQueue* setup_signal_queue)
+ : pr_context(pr_context),
+ pr_thread(pr_thread),
+ pr_entry_point(pr_entry_point),
+ setup_signal_queue(setup_signal_queue) {}
+ void* pr_context;
+ PRThread* pr_thread;
+ PRThreadEntryPoint pr_entry_point;
+ SetupSignalQueue* setup_signal_queue;
+};
+
+// The thread local key that corresponds to where local PRThread* data is held.
+SbThreadLocalKey g_pr_thread_local_key = kSbThreadLocalKeyInvalid;
+// The SbOnceControlStructure to to ensure that the local key is only created
+// once.
+SbOnceControl g_pr_thread_key_once_control = SB_ONCE_INITIALIZER;
+
+void PrThreadDtor(void* value) {
+ PRThread* pr_thread = reinterpret_cast<PRThread*>(value);
+ delete pr_thread;
+}
+
+void InitPrThreadKey() {
+ g_pr_thread_local_key = SbThreadCreateLocalKey(PrThreadDtor);
+}
+
+SbThreadLocalKey GetPrThreadKey() {
+ SB_CHECK(SbOnce(&g_pr_thread_key_once_control, InitPrThreadKey));
+ return g_pr_thread_local_key;
+}
+
+void* ThreadEntryPointWrapper(void* context_as_void_pointer) {
+ ThreadEntryPointWrapperContext* context =
+ reinterpret_cast<ThreadEntryPointWrapperContext*>(
+ context_as_void_pointer);
+ void* pr_context = context->pr_context;
+ PRThreadEntryPoint pr_entry_point = context->pr_entry_point;
+ PRThread* pr_thread = context->pr_thread;
+ SetupSignalQueue* setup_signal_queue = context->setup_signal_queue;
+
+ delete context;
+
+ pr_thread->sb_thread = SbThreadGetCurrent();
+ SbThreadLocalKey key = GetPrThreadKey();
+ SB_CHECK(SbThreadIsValidLocalKey(key));
+ SbThreadSetLocalValue(key, pr_thread);
+
+ setup_signal_queue->Put(true);
+ pr_entry_point(pr_context);
+
+ return NULL;
+}
+
+} // namespace
+
+PRLock* PR_NewLock() {
+ PRLock* lock = new PRLock();
+ if (!SbMutexCreate(lock)) {
+ delete lock;
+ return NULL;
+ }
+ return lock;
+}
+
+void PR_DestroyLock(PRLock* lock) {
+ SB_DCHECK(lock);
+ SbMutexDestroy(lock);
+ delete lock;
+}
+
+PRCondVar* PR_NewCondVar(PRLock* lock) {
+ SB_DCHECK(lock);
+ PRCondVar* cvar = new PRCondVar();
+ if (!SbConditionVariableCreate(&cvar->sb_condition_variable, lock)) {
+ delete cvar;
+ return NULL;
+ }
+ cvar->lock = lock;
+ return cvar;
+}
+
+void PR_DestroyCondVar(PRCondVar* cvar) {
+ SbConditionVariableDestroy(&cvar->sb_condition_variable);
+ delete cvar;
+}
+
+PRStatus PR_WaitCondVar(PRCondVar* cvar, PRIntervalTime timeout) {
+ SbConditionVariableResult result;
+ if (timeout == PR_INTERVAL_NO_WAIT) {
+ result = SbConditionVariableWaitTimed(&cvar->sb_condition_variable,
+ cvar->lock, 0);
+ } else if (timeout == PR_INTERVAL_NO_TIMEOUT) {
+ result = SbConditionVariableWait(&cvar->sb_condition_variable, cvar->lock);
+ } else {
+ int64_t microseconds = PR_IntervalToMicrosecondsInt64(timeout);
+ result = SbConditionVariableWaitTimed(&cvar->sb_condition_variable,
+ cvar->lock, microseconds);
+ }
+ return pr_starboard::ToPRStatus(result != kSbConditionVariableFailed);
+}
+
+PRThread* PR_GetCurrentThread() {
+ SbThreadLocalKey key = GetPrThreadKey();
+ SB_CHECK(SbThreadIsValidLocalKey(key));
+
+ PRThread* value = static_cast<PRThread*>(SbThreadGetLocalValue(key));
+ // We could potentially be a thread that was not created through
+ // PR_CreateThread. In this case, we must allocate a PRThread and do the
+ // setup that would normally have been done in PR_CreateThread.
+ if (!value) {
+ PRThread* pr_thread = new PRThread(SbThreadGetCurrent());
+ SbThreadSetLocalValue(key, pr_thread);
+ value = pr_thread;
+ }
+
+ return value;
+}
+
+uint32_t PR_snprintf(char* out, uint32_t outlen, const char* fmt, ...) {
+ va_list args;
+ va_start(args, fmt);
+ uint32_t ret = PR_vsnprintf(out, outlen, fmt, args);
+ va_end(args);
+ return ret;
+}
+
+PRThread* PR_CreateThread(PRThreadType type,
+ PRThreadEntryPoint start,
+ void* arg,
+ PRThreadPriority priority,
+ PRThreadScope scope,
+ PRThreadState state,
+ PRUint32 stackSize) {
+ int64_t sb_stack_size = static_cast<int64_t>(stackSize);
+
+ SbThreadPriority sb_priority;
+ switch (priority) {
+ case PR_PRIORITY_LOW:
+ sb_priority = kSbThreadPriorityLow;
+ break;
+ case PR_PRIORITY_NORMAL:
+ sb_priority = kSbThreadPriorityNormal;
+ break;
+ case PR_PRIORITY_HIGH:
+ sb_priority = kSbThreadPriorityHigh;
+ break;
+ case PR_PRIORITY_LAST:
+ sb_priority = kSbThreadPriorityHighest;
+ break;
+ default:
+ sb_priority = kSbThreadNoPriority;
+ }
+
+ SbThreadAffinity sb_affinity = kSbThreadNoAffinity;
+
+ SB_DCHECK(state == PR_JOINABLE_THREAD || state == PR_UNJOINABLE_THREAD);
+ bool sb_joinable = (state == PR_JOINABLE_THREAD);
+
+ // This heap allocated PRThread object will have a pointer to it stored in
+ // the newly created child thread's thread local storage. Once the newly
+ // created child thread finishes, it will be freed in the destructor
+ // associated with it through thread local storage.
+ PRThread* pr_thread = new PRThread(kSbThreadInvalid);
+
+ // Utility queue for the ThreadEntryWrapper to signal us once it's done
+ // running its initial setup and we can safely exit.
+ SetupSignalQueue setup_signal_queue;
+
+ // This heap allocated context object is freed after
+ // ThreadEntryPointWrapper's initial setup is complete, right before the
+ // nspr level entry point is run.
+ ThreadEntryPointWrapperContext* context = new ThreadEntryPointWrapperContext(
+ arg, pr_thread, start, &setup_signal_queue);
+
+ // Note that pr_thread->sb_thread will be set to the correct value in the
+ // setup section of ThreadEntryPointWrapper. It is done there rather than
+ // here to account for the unlikely but possible case in which we enter the
+ // newly created child thread, and then the child thread passes references
+ // to itself off into its potential children or co-threads that interact
+ // with it before we can copy what SbThreadCreate returns into
+ // pr_thread->sb_thread from this current thread.
+ SbThreadCreate(sb_stack_size, sb_priority, sb_affinity, sb_joinable, NULL,
+ ThreadEntryPointWrapper, context);
+
+ // Now we must wait for the setup section of ThreadEntryPointWrapper to run
+ // and initialize pr_thread (both the struct itself and the corresponding
+ // new thread's private data) before we can safely return. We expect to
+ // receive true rather than false by convention.
+ bool setup_signal = setup_signal_queue.Get();
+ SB_DCHECK(setup_signal);
+
+ return pr_thread;
+}
+
+PRStatus PR_CallOnceWithArg(PRCallOnceType* once,
+ PRCallOnceWithArgFN func,
+ void* arg) {
+ SB_NOTREACHED() << "Not implemented";
+ return PR_FAILURE;
+}
+
+PRStatus PR_NewThreadPrivateIndex(PRTLSIndex* newIndex,
+ PRThreadPrivateDTOR destructor) {
+ SbThreadLocalKey key = SbThreadCreateLocalKey(destructor);
+ if (!SbThreadIsValidLocalKey(key)) {
+ return pr_starboard::ToPRStatus(false);
+ }
+ *newIndex = key;
+ return pr_starboard::ToPRStatus(true);
+}
+
+PRIntervalTime PR_MillisecondsToInterval(PRUint32 milli) {
+ PRUint64 tock = static_cast<PRUint64>(milli);
+ PRUint64 msecPerSec = static_cast<PRInt64>(PR_MSEC_PER_SEC);
+ PRUint64 rounding = static_cast<PRInt64>(PR_MSEC_PER_SEC >> 1);
+ PRUint64 tps = static_cast<PRInt64>(PR_TicksPerSecond());
+
+ tock *= tps;
+ tock += rounding;
+ tock /= msecPerSec;
+
+ PRUint64 ticks = static_cast<PRUint64>(tock);
+ return ticks;
+}
+
+PRUint32 PR_IntervalToMicroseconds(PRIntervalTime ticks) {
+ PRUint64 tock = static_cast<PRInt64>(ticks);
+ PRUint64 usecPerSec = static_cast<PRInt64>(PR_USEC_PER_SEC);
+ PRUint64 tps = static_cast<PRInt64>(PR_TicksPerSecond());
+ PRUint64 rounding = static_cast<PRUint64>(tps) >> 1;
+
+ tock *= usecPerSec;
+ tock += rounding;
+ tock /= tps;
+
+ PRUint32 micro = static_cast<PRUint32>(tock);
+ return micro;
+}
diff --git a/src/starboard/client_porting/pr_starboard/pr_starboard.gyp b/src/starboard/client_porting/pr_starboard/pr_starboard.gyp
new file mode 100644
index 0000000..0874b65
--- /dev/null
+++ b/src/starboard/client_porting/pr_starboard/pr_starboard.gyp
@@ -0,0 +1,29 @@
+# Copyright 2016 Google Inc. All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+{
+ 'targets': [
+ {
+ 'target_name': 'pr_starboard',
+ 'type': 'static_library',
+ 'sources': [
+ 'pr_starboard.cc',
+ 'pr_starboard.h',
+ ],
+ 'dependencies': [
+ '<(DEPTH)/starboard/starboard.gyp:starboard',
+ ],
+ },
+ ],
+}
diff --git a/src/starboard/client_porting/pr_starboard/pr_starboard.h b/src/starboard/client_porting/pr_starboard/pr_starboard.h
new file mode 100644
index 0000000..63e5c4d
--- /dev/null
+++ b/src/starboard/client_porting/pr_starboard/pr_starboard.h
@@ -0,0 +1,189 @@
+// Copyright 2016 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+// This header defines the interface for a starboard based implementation of
+// the subset of nspr that SpiderMonkey depends on. It directly matches the
+// NSPR API, with the exception that accessing thread local data should use
+// PRTLSIndex, rather than PRUintn.
+
+#ifndef STARBOARD_CLIENT_PORTING_PR_STARBOARD_PR_STARBOARD_H_
+#define STARBOARD_CLIENT_PORTING_PR_STARBOARD_PR_STARBOARD_H_
+
+#include "starboard/condition_variable.h"
+#include "starboard/log.h"
+#include "starboard/memory.h"
+#include "starboard/mutex.h"
+#include "starboard/string.h"
+#include "starboard/thread.h"
+#include "starboard/types.h"
+
+#define PR_CALLBACK
+
+#define PR_MSEC_PER_SEC 1000L
+#define PR_USEC_PER_SEC 1000000L
+#define PR_NSEC_PER_SEC 1000000000L
+#define PR_USEC_PER_MSEC 1000L
+#define PR_NSEC_PER_MSEC 1000000L
+
+typedef enum { PR_FAILURE = -1, PR_SUCCESS = 0 } PRStatus;
+
+namespace pr_starboard {
+
+// Utility function to map true to PR_SUCCESS and false to PR_FAILURE.
+static inline PRStatus ToPRStatus(bool result) {
+ return result ? PR_SUCCESS : PR_FAILURE;
+}
+
+} // namespace pr_starboard
+
+typedef enum PRThreadPriority {
+ PR_PRIORITY_FIRST = 0,
+ PR_PRIORITY_LOW = 0,
+ PR_PRIORITY_NORMAL = 1,
+ PR_PRIORITY_HIGH = 2,
+ PR_PRIORITY_URGENT = 3,
+ PR_PRIORITY_LAST = 3
+} PRThreadPriority;
+
+typedef enum PRThreadScope {
+ PR_LOCAL_THREAD,
+ PR_GLOBAL_THREAD,
+ PR_GLOBAL_BOUND_THREAD
+} PRThreadScope;
+
+typedef enum PRThreadState {
+ PR_JOINABLE_THREAD,
+ PR_UNJOINABLE_THREAD
+} PRThreadState;
+
+typedef enum PRThreadType { PR_USER_THREAD, PR_SYSTEM_THREAD } PRThreadType;
+
+typedef SbThreadLocalKey PRTLSIndex;
+typedef uint32_t PRIntervalTime;
+
+typedef int32_t PRInt32;
+typedef uint32_t PRUint32;
+
+typedef int64_t PRInt64;
+typedef uint64_t PRUint64;
+
+typedef void(PR_CALLBACK* PRThreadPrivateDTOR)(void* priv);
+
+struct PRThread {
+ explicit PRThread(SbThread sb_thread) : sb_thread(sb_thread) {}
+ SbThread sb_thread;
+};
+
+typedef SbMutex PRLock;
+
+#define PR_INTERVAL_NO_WAIT 0UL
+#define PR_INTERVAL_NO_TIMEOUT 0xffffffffUL
+
+struct PRCondVar {
+ SbConditionVariable sb_condition_variable;
+ SbMutex* lock;
+};
+
+PRLock* PR_NewLock();
+
+static inline void PR_Lock(PRLock* lock) {
+ SbMutexAcquire(lock);
+}
+
+static inline void PR_Unlock(PRLock* lock) {
+ SbMutexRelease(lock);
+}
+
+void PR_DestroyLock(PRLock* lock);
+
+PRCondVar* PR_NewCondVar(PRLock* lock);
+
+void PR_DestroyCondVar(PRCondVar* cvar);
+
+PRStatus PR_WaitCondVar(PRCondVar* cvar, PRIntervalTime timeout);
+
+static inline PRStatus PR_NotifyCondVar(PRCondVar* cvar) {
+ return pr_starboard::ToPRStatus(
+ SbConditionVariableSignal(&cvar->sb_condition_variable));
+}
+
+static inline PRStatus PR_NotifyAllCondVar(PRCondVar* cvar) {
+ return pr_starboard::ToPRStatus(
+ SbConditionVariableBroadcast(&cvar->sb_condition_variable));
+}
+
+typedef void (*PRThreadEntryPoint)(void*);
+
+PRThread* PR_CreateThread(PRThreadType type,
+ PRThreadEntryPoint start,
+ void* arg,
+ PRThreadPriority priority,
+ PRThreadScope scope,
+ PRThreadState state,
+ PRUint32 stackSize);
+
+static inline PRStatus PR_JoinThread(PRThread* pr_thread) {
+ SB_DCHECK(pr_thread);
+ SB_DCHECK(SbThreadIsValid(pr_thread->sb_thread));
+ return pr_starboard::ToPRStatus(SbThreadJoin(pr_thread->sb_thread, NULL));
+}
+
+PRThread* PR_GetCurrentThread();
+
+void PR_DetachThread();
+
+PRStatus PR_NewThreadPrivateIndex(PRTLSIndex* newIndex,
+ PRThreadPrivateDTOR destructor);
+
+static inline PRStatus PR_SetThreadPrivate(PRTLSIndex index, void* priv) {
+ return pr_starboard::ToPRStatus(SbThreadSetLocalValue(index, priv));
+}
+
+static inline void* PR_GetThreadPrivate(PRTLSIndex index) {
+ return SbThreadGetLocalValue(index);
+}
+
+static inline void PR_SetCurrentThreadName(const char* name) {
+ SbThreadSetName(name);
+}
+
+static inline PRUint32 PR_vsnprintf(char* out,
+ PRUint32 outlen,
+ const char* fmt,
+ va_list ap) {
+ return static_cast<PRUint32>(SbStringFormat(out, outlen, fmt, ap));
+}
+
+PRUint32 PR_snprintf(char* out, PRUint32 outlen, const char* fmt, ...);
+
+PRIntervalTime PR_MillisecondsToInterval(PRUint32 milli);
+
+static inline PRIntervalTime PR_MicrosecondsToInterval(PRUint32 micro) {
+ return (micro + 999) / 1000;
+}
+
+PRUint32 PR_IntervalToMicroseconds(PRIntervalTime ticks);
+
+struct PRCallOnceType {};
+typedef PRStatus(PR_CALLBACK* PRCallOnceWithArgFN)(void* arg);
+
+PRStatus PR_CallOnceWithArg(PRCallOnceType* once,
+ PRCallOnceWithArgFN func,
+ void* arg);
+
+static inline PRUint32 PR_TicksPerSecond() {
+ return 1000;
+}
+
+#endif // STARBOARD_CLIENT_PORTING_PR_STARBOARD_PR_STARBOARD_H_
diff --git a/src/starboard/client_porting/wrap_main/wrap_main.h b/src/starboard/client_porting/wrap_main/wrap_main.h
index e4879d3..4734772 100644
--- a/src/starboard/client_porting/wrap_main/wrap_main.h
+++ b/src/starboard/client_porting/wrap_main/wrap_main.h
@@ -50,6 +50,11 @@
} // namespace client_porting
} // namespace starboard
+#if defined(_WIN32)
+// Today there is no Starboard win32. Make sure those who create it know
+// the _CrtSet* functions below should be moved to starboard win32 main.
+#error For starboard win32, please move _CrtSet* to main
+#endif
#define STARBOARD_WRAP_SIMPLE_MAIN(main_function) \
void SbEventHandle(const SbEvent* event) { \
::starboard::client_porting::wrap_main::SimpleEventHandler< \
@@ -57,10 +62,26 @@
}
#else
+#if defined(_WIN32)
+#include <windows.h>
+
+// TODO this case should be removed when win32 is starboardized
+#define STARBOARD_WRAP_SIMPLE_MAIN(main_function) \
+ int main(int argc, char** argv) { \
+ if (!IsDebuggerPresent()) { \
+ _CrtSetReportMode(_CRT_ASSERT, _CRTDBG_MODE_FILE | _CRTDBG_MODE_DEBUG); \
+ _CrtSetReportMode(_CRT_ERROR, _CRTDBG_MODE_FILE | _CRTDBG_MODE_DEBUG); \
+ _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE | _CRTDBG_MODE_DEBUG); \
+ _CrtSetReportFile(_CRT_ASSERT, _CRTDBG_FILE_STDERR); \
+ } \
+ return main_function(argc, argv); \
+ }
+#else // defined(_WIN32)
#define STARBOARD_WRAP_SIMPLE_MAIN(main_function) \
int main(int argc, char** argv) { \
return main_function(argc, argv); \
}
+#endif
#endif // STARBOARD
#endif // STARBOARD_CLIENT_PORTING_WRAP_MAIN_WRAP_MAIN_H_
diff --git a/src/starboard/condition_variable.h b/src/starboard/condition_variable.h
index 673b7d9..4c519ba 100644
--- a/src/starboard/condition_variable.h
+++ b/src/starboard/condition_variable.h
@@ -56,10 +56,6 @@
// placing the newly created condition variable in |out_condition|.
//
// The return value indicates whether the condition variable could be created.
-//
-// TODO: It looks like WTF does not have the mutex available when creating
-// the condition variable, and pthreads doesn't appear to require the mutex on
-// condvar creation, so we should just remove the parameter.
SB_EXPORT bool SbConditionVariableCreate(SbConditionVariable* out_condition,
SbMutex* opt_mutex);
diff --git a/src/starboard/examples/window/main.cc b/src/starboard/examples/window/main.cc
index 381d428..bb5bc83 100644
--- a/src/starboard/examples/window/main.cc
+++ b/src/starboard/examples/window/main.cc
@@ -35,7 +35,7 @@
<< ", window=" << data->window
<< ", device_type=" << data->device_type
<< ", device_id=" << data->device_id
- << ", key=" << data->key
+ << ", key=0x" << std::hex << data->key
<< ", character=" << data->character
<< ", modifiers=0x" << std::hex << data->key_modifiers
<< ", location=" << std::dec << data->key_location;
diff --git a/src/starboard/linux/x64directfb/sanitizer_options.cc b/src/starboard/linux/x64directfb/sanitizer_options.cc
new file mode 100644
index 0000000..e85d451
--- /dev/null
+++ b/src/starboard/linux/x64directfb/sanitizer_options.cc
@@ -0,0 +1,42 @@
+// Copyright 2016 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+// Removes gallium leak warnings from x11 GL code, but defines it as a weak
+// symbol, so other code can override it if they want to.
+
+#if defined(ADDRESS_SANITIZER)
+
+// Functions returning default options are declared weak in the tools' runtime
+// libraries. To make the linker pick the strong replacements for those
+// functions from this module, we explicitly force its inclusion by passing
+// -Wl,-u_sanitizer_options_link_helper
+extern "C" void _sanitizer_options_link_helper() { }
+
+#define SANITIZER_HOOK_ATTRIBUTE \
+ extern "C" \
+ __attribute__((no_sanitize_address)) \
+ __attribute__((no_sanitize_memory)) \
+ __attribute__((no_sanitize_thread)) \
+ __attribute__((visibility("default"))) \
+ __attribute__((weak)) \
+ __attribute__((used))
+
+// Newline separated list of issues to suppress, see
+// http://clang.llvm.org/docs/AddressSanitizer.html#issue-suppression
+// http://llvm.org/svn/llvm-project/compiler-rt/trunk/lib/sanitizer_common/sanitizer_suppressions.cc
+SANITIZER_HOOK_ATTRIBUTE const char* __lsan_default_suppressions() {
+ return "leak:*eglibc-2.19*\n";
+}
+
+#endif // defined(ADDRESS_SANITIZER)
diff --git a/src/starboard/linux/x64directfb/starboard_platform.gypi b/src/starboard/linux/x64directfb/starboard_platform.gypi
index f5d40ad..d38e23c 100644
--- a/src/starboard/linux/x64directfb/starboard_platform.gypi
+++ b/src/starboard/linux/x64directfb/starboard_platform.gypi
@@ -17,6 +17,7 @@
'variables': {
'starboard_platform_sources': [
'<(DEPTH)/starboard/linux/x64directfb/main.cc',
+ '<(DEPTH)/starboard/linux/x64directfb/sanitizer_options.cc',
'<(DEPTH)/starboard/linux/x64directfb/system_get_property.cc',
'<(DEPTH)/starboard/shared/directfb/application_directfb.cc',
'<(DEPTH)/starboard/shared/directfb/blitter_blit_rect_to_rect.cc',
diff --git a/src/starboard/nplb/decode_target_create_test.cc b/src/starboard/nplb/decode_target_create_test.cc
index e8f3ea4..287dc21 100644
--- a/src/starboard/nplb/decode_target_create_test.cc
+++ b/src/starboard/nplb/decode_target_create_test.cc
@@ -44,7 +44,6 @@
SbDecodeTarget target =
SbDecodeTargetCreate(kSbDecodeTargetFormat1PlaneRGBA, &surface);
- EXPECT_TRUE(SbDecodeTargetIsValid(target));
if (SbDecodeTargetIsValid(target)) {
SbBlitterSurface plane =
SbDecodeTargetGetPlane(target, kSbDecodeTargetPlaneRGBA);
diff --git a/src/starboard/nplb/storage_helpers.h b/src/starboard/nplb/storage_helpers.h
index 56b4fc2..efc422e 100644
--- a/src/starboard/nplb/storage_helpers.h
+++ b/src/starboard/nplb/storage_helpers.h
@@ -27,12 +27,12 @@
const int64_t kStorageSize2 = kStorageSize * 2 + kStorageOffset;
// Deletes the storage for the current user.
-SB_C_INLINE void ClearStorageRecord() {
+static SB_C_INLINE void ClearStorageRecord() {
SbStorageDeleteRecord(SbUserGetCurrent());
}
// Opens the storage record for the current user, validating that it is valid.
-SB_C_INLINE SbStorageRecord OpenStorageRecord() {
+static SB_C_INLINE SbStorageRecord OpenStorageRecord() {
SbStorageRecord record = SbStorageOpenRecord(SbUserGetCurrent());
EXPECT_TRUE(SbStorageIsValidRecord(record));
return record;
@@ -40,7 +40,8 @@
// Writes a standard pattern of |size| bytes into the given open storage
// |record|.
-SB_C_INLINE void WriteStorageRecord(SbStorageRecord record, int64_t size) {
+static SB_C_INLINE void WriteStorageRecord(SbStorageRecord record,
+ int64_t size) {
char* data = new char[size];
for (int64_t i = 0; i < size; ++i) {
data[i] = static_cast<char>(i + 2 % 0xFF);
@@ -52,7 +53,8 @@
// Ensures that the storage record for the current user is initialized with the
// standard pattern for exactly |length| bytes.
-SB_C_INLINE void InitializeStorageRecord(int64_t length) {
+
+static SB_C_INLINE void InitializeStorageRecord(int64_t length) {
ClearStorageRecord();
SbStorageRecord record = OpenStorageRecord();
WriteStorageRecord(record, length);
@@ -62,7 +64,7 @@
// Checks a buffer of |total| size for the expected pattern (written in
// WriteStorageRecord) to start at |offset| and continue for |length|, and the
// rest of the buffer, before and after, should be set to 0.
-SB_C_INLINE void CheckStorageBuffer(char* data,
+static SB_C_INLINE void CheckStorageBuffer(char* data,
int64_t offset,
int64_t length,
int64_t total) {
@@ -83,7 +85,7 @@
// |offset| and reporting the buffer size as |length|, checks that the number of
// read bytes is |expected_length| and then checks the buffer for the expected
// pattern written in WriteStorageRecord over the expected range of the buffer.
-SB_C_INLINE void ReadAndCheckStorage(SbStorageRecord record,
+static SB_C_INLINE void ReadAndCheckStorage(SbStorageRecord record,
int64_t offset,
int64_t expected_length,
int64_t length,
diff --git a/src/starboard/player.h b/src/starboard/player.h
index 6fbc381..cbd1ff3 100644
--- a/src/starboard/player.h
+++ b/src/starboard/player.h
@@ -173,7 +173,7 @@
#define kSbPlayerInvalid ((SbPlayer)NULL)
// Returns whether the given player handle is valid.
-SB_C_INLINE bool SbPlayerIsValid(SbPlayer player) {
+static SB_C_INLINE bool SbPlayerIsValid(SbPlayer player) {
return player != kSbPlayerInvalid;
}
diff --git a/src/starboard/raspi/1/gyp_configuration.gypi b/src/starboard/raspi/1/gyp_configuration.gypi
index fbccc08..040ca1e 100644
--- a/src/starboard/raspi/1/gyp_configuration.gypi
+++ b/src/starboard/raspi/1/gyp_configuration.gypi
@@ -32,7 +32,8 @@
# This should have a default value in cobalt/base.gypi. See the comment
# there for acceptable values for this variable.
'javascript_engine': 'mozjs',
- 'cobalt_enable_jit': 1,
+ 'cobalt_enable_jit': 0,
+ 'cobalt_minimum_frame_time_in_milliseconds': '33',
# RasPi 1 is ARMv6
'arm_version': 6,
diff --git a/src/starboard/raspi/1/starboard_platform.gyp b/src/starboard/raspi/1/starboard_platform.gyp
index fb203a6..c39d4e3 100644
--- a/src/starboard/raspi/1/starboard_platform.gyp
+++ b/src/starboard/raspi/1/starboard_platform.gyp
@@ -39,6 +39,8 @@
'<(DEPTH)/starboard/raspi/shared/main.cc',
'<(DEPTH)/starboard/raspi/shared/open_max/open_max_component.cc',
'<(DEPTH)/starboard/raspi/shared/open_max/open_max_component.h',
+ '<(DEPTH)/starboard/raspi/shared/open_max/open_max_video_decode_component.cc',
+ '<(DEPTH)/starboard/raspi/shared/open_max/open_max_video_decode_component.h',
'<(DEPTH)/starboard/raspi/shared/open_max/video_decoder.cc',
'<(DEPTH)/starboard/raspi/shared/open_max/video_decoder.h',
'<(DEPTH)/starboard/raspi/shared/thread_create_priority.cc',
diff --git a/src/starboard/raspi/shared/application_dispmanx.cc b/src/starboard/raspi/shared/application_dispmanx.cc
index fcaf43f..4f9dddf 100644
--- a/src/starboard/raspi/shared/application_dispmanx.cc
+++ b/src/starboard/raspi/shared/application_dispmanx.cc
@@ -51,9 +51,7 @@
window_ = new SbWindowPrivate(*display_, options);
input_ = DevInput::Create(window_);
- // Create the dispmanx element to display video frames.
- int result = 0;
- uint32_t vc_image_ptr;
+ video_renderer_.reset(new DispmanxVideoRenderer(*display_, kVideoLayer));
return window_;
}
@@ -86,14 +84,11 @@
}
void ApplicationDispmanx::AcceptFrame(SbPlayer player,
- const VideoFrame& frame,
+ const scoped_refptr<VideoFrame>& frame,
int x,
int y,
int width,
int height) {
- if (!video_renderer_) {
- video_renderer_.reset(new DispmanxVideoRenderer(*display_, kVideoLayer));
- }
video_renderer_->Update(frame);
}
diff --git a/src/starboard/raspi/shared/application_dispmanx.h b/src/starboard/raspi/shared/application_dispmanx.h
index ba49ff5..d08c406 100644
--- a/src/starboard/raspi/shared/application_dispmanx.h
+++ b/src/starboard/raspi/shared/application_dispmanx.h
@@ -49,7 +49,7 @@
void Initialize() SB_OVERRIDE;
void Teardown() SB_OVERRIDE;
void AcceptFrame(SbPlayer player,
- const VideoFrame& frame,
+ const scoped_refptr<VideoFrame>& frame,
int x,
int y,
int width,
diff --git a/src/starboard/raspi/shared/dispmanx_util.cc b/src/starboard/raspi/shared/dispmanx_util.cc
index 88c7f52..f33a441 100644
--- a/src/starboard/raspi/shared/dispmanx_util.cc
+++ b/src/starboard/raspi/shared/dispmanx_util.cc
@@ -23,6 +23,8 @@
namespace {
+const int kElementChangeAttributesFlagSrcRect = 1 << 3;
+
class DispmanxAutoUpdate {
public:
DispmanxAutoUpdate() {
@@ -52,10 +54,61 @@
} // namespace
+DispmanxResource::DispmanxResource(VC_IMAGE_TYPE_T image_type,
+ uint32_t width,
+ uint32_t height,
+ uint32_t visible_width,
+ uint32_t visible_height)
+ : width_(width),
+ height_(height),
+ visible_width_(visible_width),
+ visible_height_(visible_height) {
+ static const uint32_t kMaxDimension = 1 << 16;
+
+ SB_DCHECK(width_ > 0 && width_ < kMaxDimension);
+ SB_DCHECK(height_ > 0 && height_ < kMaxDimension);
+ SB_DCHECK(visible_width_ > 0 && visible_width_ < kMaxDimension);
+ SB_DCHECK(visible_height > 0 && visible_height < kMaxDimension);
+ SB_DCHECK(width_ >= visible_width_);
+ SB_DCHECK(height_ >= visible_height);
+
+ uint32_t vc_image_ptr;
+
+ handle_ = vc_dispmanx_resource_create(
+ image_type, visible_width_ | (width_ << 16),
+ visible_height | (height_ << 16), &vc_image_ptr);
+ SB_DCHECK(handle_ != DISPMANX_NO_HANDLE);
+}
+
+void DispmanxYUV420Resource::WriteData(const void* data) {
+ SB_DCHECK(handle() != DISPMANX_NO_HANDLE);
+
+ DispmanxRect dst_rect(0, 0, width(), height() * 3 / 2);
+ int32_t result = vc_dispmanx_resource_write_data(
+ handle(), VC_IMAGE_YUV420, width(), const_cast<void*>(data), &dst_rect);
+ SB_DCHECK(result == 0);
+}
+
void DispmanxYUV420Resource::ClearWithBlack() {
- scoped_array<uint8_t> data(new uint8_t[width_ * height_ * 3 / 2]);
- SbMemorySet(data.get(), width_ * height_, 0);
- SbMemorySet(data.get() + width_ * height_, width_ * height_ / 2, 0x80);
+ scoped_array<uint8_t> data(new uint8_t[width() * height() * 3 / 2]);
+ SbMemorySet(data.get(), width() * height(), 0);
+ SbMemorySet(data.get() + width() * height(), width() * height() / 2, 0x80);
+ WriteData(data.get());
+}
+
+void DispmanxRGB565Resource::WriteData(const void* data) {
+ SB_DCHECK(handle() != DISPMANX_NO_HANDLE);
+
+ DispmanxRect dst_rect(0, 0, width(), height());
+ int32_t result =
+ vc_dispmanx_resource_write_data(handle(), VC_IMAGE_RGB565, width() * 2,
+ const_cast<void*>(data), &dst_rect);
+ SB_DCHECK(result == 0);
+}
+
+void DispmanxRGB565Resource::ClearWithBlack() {
+ scoped_array<uint8_t> data(new uint8_t[width() * height() * 2]);
+ SbMemorySet(data.get(), width() * height() * 2, 0);
WriteData(data.get());
}
@@ -78,26 +131,37 @@
SB_DCHECK(result == 0) << " result=" << result;
}
-void DispmanxVideoRenderer::Update(const VideoFrame& video_frame) {
- if (video_frame.IsEndOfStream()) {
- element_.reset();
- resource_.reset();
+void DispmanxElement::ChangeSource(const DispmanxResource& new_src) {
+ DispmanxAutoUpdate update;
+ vc_dispmanx_element_change_source(update.handle(), handle_, new_src.handle());
+}
+
+DispmanxVideoRenderer::DispmanxVideoRenderer(const DispmanxDisplay& display,
+ int32_t layer)
+ : black_frame_(256, 256, 256, 256) {
+ black_frame_.ClearWithBlack();
+ element_.reset(new DispmanxElement(display, layer, DispmanxRect(),
+ black_frame_, DispmanxRect()));
+}
+
+void DispmanxVideoRenderer::Update(
+ const scoped_refptr<VideoFrame>& video_frame) {
+ SB_DCHECK(video_frame);
+
+ if (frame_ == video_frame) {
return;
}
- if (!resource_ || resource_->width() != video_frame.width() ||
- resource_->height() != video_frame.height()) {
- element_.reset();
- resource_.reset();
- DispmanxRect src_rect(0, 0, video_frame.width() << 16,
- video_frame.height() << 16);
- resource_.reset(
- new DispmanxYUV420Resource(video_frame.width(), video_frame.height()));
- element_.reset(new DispmanxElement(display_, layer_, DispmanxRect(),
- *resource_, src_rect));
+ if (video_frame->IsEndOfStream()) {
+ element_->ChangeSource(black_frame_);
+ frame_ = video_frame;
+ return;
}
- resource_->WriteData(video_frame.GetPlane(0).data);
+ DispmanxYUV420Resource* resource =
+ reinterpret_cast<DispmanxYUV420Resource*>(video_frame->native_texture());
+ element_->ChangeSource(*resource);
+ frame_ = video_frame;
}
} // namespace shared
diff --git a/src/starboard/raspi/shared/dispmanx_util.h b/src/starboard/raspi/shared/dispmanx_util.h
index c4b65f6..f051e86 100644
--- a/src/starboard/raspi/shared/dispmanx_util.h
+++ b/src/starboard/raspi/shared/dispmanx_util.h
@@ -69,38 +69,57 @@
}
DISPMANX_RESOURCE_HANDLE_T handle() const { return handle_; }
+ uint32_t visible_width() const { return visible_width_; }
+ uint32_t visible_height() const { return visible_height_; }
uint32_t width() const { return width_; }
uint32_t height() const { return height_; }
protected:
- DispmanxResource(VC_IMAGE_TYPE_T image_type, uint32_t width, uint32_t height)
- : width_(width), height_(height) {
- uint32_t vc_image_ptr;
+ DispmanxResource(VC_IMAGE_TYPE_T image_type,
+ uint32_t width,
+ uint32_t height,
+ uint32_t visible_width,
+ uint32_t visible_height);
- handle_ =
- vc_dispmanx_resource_create(image_type, width, height, &vc_image_ptr);
- SB_DCHECK(handle_ != DISPMANX_NO_HANDLE);
- }
-
+ private:
DISPMANX_RESOURCE_HANDLE_T handle_;
uint32_t width_;
uint32_t height_;
+ uint32_t visible_width_;
+ uint32_t visible_height_;
SB_DISALLOW_COPY_AND_ASSIGN(DispmanxResource);
};
class DispmanxYUV420Resource : public DispmanxResource {
public:
- DispmanxYUV420Resource(uint32_t width, uint32_t height)
- : DispmanxResource(VC_IMAGE_YUV420, width, height) {}
+ DispmanxYUV420Resource(uint32_t width,
+ uint32_t height,
+ uint32_t visible_width,
+ uint32_t visible_height)
+ : DispmanxResource(VC_IMAGE_YUV420,
+ width,
+ height,
+ visible_width,
+ visible_height) {}
- void WriteData(const void* data) {
- SB_DCHECK(handle_ != DISPMANX_NO_HANDLE);
- DispmanxRect dst_rect(0, 0, width(), height() * 3 / 2);
- int32_t result = vc_dispmanx_resource_write_data(
- handle_, VC_IMAGE_YUV420, width(), const_cast<void*>(data), &dst_rect);
- SB_DCHECK(result == 0);
- }
+ void WriteData(const void* data);
+ void ClearWithBlack();
+};
+
+class DispmanxRGB565Resource : public DispmanxResource {
+ public:
+ DispmanxRGB565Resource(uint32_t width,
+ uint32_t height,
+ uint32_t visible_width,
+ uint32_t visible_height)
+ : DispmanxResource(VC_IMAGE_RGB565,
+ width,
+ height,
+ visible_width,
+ visible_height) {}
+
+ void WriteData(const void* data);
void ClearWithBlack();
};
@@ -114,6 +133,7 @@
~DispmanxElement();
DISPMANX_ELEMENT_HANDLE_T handle() const { return handle_; }
+ void ChangeSource(const DispmanxResource& new_src);
private:
DISPMANX_ELEMENT_HANDLE_T handle_;
@@ -124,16 +144,18 @@
class DispmanxVideoRenderer {
public:
typedef starboard::shared::starboard::player::VideoFrame VideoFrame;
- DispmanxVideoRenderer(const DispmanxDisplay& display, int32_t layer)
- : display_(display), layer_(layer) {}
- void Update(const VideoFrame& video_frame);
+ DispmanxVideoRenderer(const DispmanxDisplay& display, int32_t layer);
+
+ void Update(const scoped_refptr<VideoFrame>& video_frame);
private:
- const DispmanxDisplay& display_;
- int32_t layer_;
- scoped_ptr<DispmanxYUV420Resource> resource_;
scoped_ptr<DispmanxElement> element_;
+ scoped_refptr<VideoFrame> frame_;
+
+ // Used to fill the background with black if no video is playing so that the
+ // console does not show through.
+ DispmanxRGB565Resource black_frame_;
SB_DISALLOW_COPY_AND_ASSIGN(DispmanxVideoRenderer);
};
diff --git a/src/starboard/raspi/shared/open_max/open_max_component.cc b/src/starboard/raspi/shared/open_max/open_max_component.cc
index eb05825..bb814f6c 100644
--- a/src/starboard/raspi/shared/open_max/open_max_component.cc
+++ b/src/starboard/raspi/shared/open_max/open_max_component.cc
@@ -47,15 +47,13 @@
} // namespace
-OpenMaxComponent::OpenMaxComponent(const char* name, size_t minimum_output_size)
+OpenMaxComponent::OpenMaxComponent(const char* name)
: condition_variable_(mutex_),
- minimum_output_size_(minimum_output_size),
handle_(NULL),
input_port_(kInvalidPort),
output_port_(kInvalidPort),
output_setting_changed_(false),
- output_buffer_(NULL),
- output_buffer_filled_(false) {
+ output_port_enabled_(false) {
InitializeOpenMax();
OMX_CALLBACKTYPE callbacks;
@@ -99,18 +97,20 @@
SendCommandAndWaitForCompletion(OMX_CommandFlush, output_port_);
SendCommand(OMX_CommandPortDisable, input_port_);
- for (BufferHeaders::iterator iter = unused_buffers_.begin();
- iter != unused_buffers_.end(); ++iter) {
- OMX_ERRORTYPE error = OMX_FreeBuffer(handle_, input_port_, *iter);
+ for (size_t i = 0; i < input_buffers_.size(); ++i) {
+ OMX_ERRORTYPE error =
+ OMX_FreeBuffer(handle_, input_port_, input_buffers_[i]);
SB_DCHECK(error == OMX_ErrorNone);
}
WaitForCommandCompletion();
SendCommand(OMX_CommandPortDisable, output_port_);
- if (output_buffer_) {
- OMX_ERRORTYPE error = OMX_FreeBuffer(handle_, output_port_, output_buffer_);
+ for (size_t i = 0; i < output_buffers_.size(); ++i) {
+ OMX_ERRORTYPE error =
+ OMX_FreeBuffer(handle_, output_port_, output_buffers_[i]);
SB_DCHECK(error == OMX_ErrorNone);
}
+ output_buffers_.clear();
WaitForCommandCompletion();
SendCommandAndWaitForCompletion(OMX_CommandStateSet, OMX_StateLoaded);
@@ -162,45 +162,34 @@
SB_DCHECK(error == OMX_ErrorNone);
}
-bool OpenMaxComponent::ReadVideoFrame(VideoFrame* frame) {
+OMX_BUFFERHEADERTYPE* OpenMaxComponent::PeekNextOutputBuffer() {
{
ScopedLock scoped_lock(mutex_);
- if (output_buffer_ && !output_buffer_filled_) {
- return false;
- }
+
if (!output_setting_changed_) {
- return false;
+ return NULL;
}
}
- SB_DCHECK(output_setting_changed_);
- if (!output_buffer_) {
- GetOutputPortParam(&output_port_definition_);
- SB_DCHECK(output_port_definition_.format.video.eColorFormat ==
- OMX_COLOR_FormatYUV420PackedPlanar);
- EnableOutputPortAndAllocateBuffer();
- return false;
- }
- if (output_buffer_->nFlags & OMX_BUFFERFLAG_EOS) {
- *frame = VideoFrame();
- return true;
+ if (!output_port_enabled_) {
+ EnableOutputPortAndAllocateBuffer();
}
- SbMediaTime timestamp =
- ((output_buffer_->nTimeStamp.nHighPart * 0x100000000ull) +
- output_buffer_->nTimeStamp.nLowPart) *
- kSbMediaTimeSecond / kSbTimeSecond;
- int width = output_port_definition_.format.video.nFrameWidth;
- int height = output_port_definition_.format.video.nSliceHeight;
- int pitch = output_port_definition_.format.video.nStride;
- *frame = VideoFrame::CreateYV12Frame(
- width, height, pitch, timestamp, output_buffer_->pBuffer,
- output_buffer_->pBuffer + pitch * height,
- output_buffer_->pBuffer + pitch * height * 5 / 4);
- output_buffer_filled_ = false;
- output_buffer_->nFilledLen = 0;
- OMX_ERRORTYPE error = OMX_FillThisBuffer(handle_, output_buffer_);
+
+ ScopedLock scoped_lock(mutex_);
+ return filled_output_buffers_.empty() ? NULL : filled_output_buffers_.front();
+}
+
+void OpenMaxComponent::DropNextOutputBuffer() {
+ OMX_BUFFERHEADERTYPE* buffer = NULL;
+ {
+ ScopedLock scoped_lock(mutex_);
+ SB_DCHECK(!filled_output_buffers_.empty());
+ buffer = filled_output_buffers_.front();
+ filled_output_buffers_.pop();
+ }
+ buffer->nFilledLen = 0;
+ OMX_ERRORTYPE error = OMX_FillThisBuffer(handle_, buffer);
SB_DCHECK(error == OMX_ErrorNone);
- return true;
}
void OpenMaxComponent::SendCommand(OMX_COMMANDTYPE command, int param) {
@@ -234,48 +223,68 @@
}
void OpenMaxComponent::EnableInputPortAndAllocateBuffers() {
- SB_DCHECK(unused_buffers_.empty());
+ SB_DCHECK(input_buffers_.empty());
OMXParamPortDefinition port_definition;
GetInputPortParam(&port_definition);
+ if (OnEnableInputPort(&port_definition)) {
+ SetPortParam(port_definition);
+ }
SendCommand(OMX_CommandPortEnable, input_port_);
- unused_buffers_.resize(port_definition.nBufferCountActual);
- for (int i = 0; i != port_definition.nBufferCountActual; ++i) {
- OMX_ERRORTYPE error =
- OMX_AllocateBuffer(handle_, &unused_buffers_[i], input_port_, NULL,
- port_definition.nBufferSize);
+ for (int i = 0; i < port_definition.nBufferCountActual; ++i) {
+ OMX_BUFFERHEADERTYPE* buffer;
+ OMX_ERRORTYPE error = OMX_AllocateBuffer(handle_, &buffer, input_port_,
+ NULL, port_definition.nBufferSize);
SB_DCHECK(error == OMX_ErrorNone);
+ input_buffers_.push_back(buffer);
+ unused_input_buffers_.push(buffer);
}
WaitForCommandCompletion();
}
void OpenMaxComponent::EnableOutputPortAndAllocateBuffer() {
- if (output_buffer_ != NULL) {
- return;
+ SB_DCHECK(!output_port_enabled_);
+
+ GetOutputPortParam(&output_port_definition_);
+ if (OnEnableOutputPort(&output_port_definition_)) {
+ SetPortParam(output_port_definition_);
}
SendCommand(OMX_CommandPortEnable, output_port_);
- OMX_ERRORTYPE error = OMX_AllocateBuffer(
- handle_, &output_buffer_, output_port_, NULL,
- std::max(output_port_definition_.nBufferSize, minimum_output_size_));
- SB_DCHECK(error == OMX_ErrorNone);
+ output_buffers_.reserve(output_port_definition_.nBufferCountActual);
+ for (int i = 0; i < output_port_definition_.nBufferCountActual; ++i) {
+ OMX_BUFFERHEADERTYPE* buffer;
+ OMX_ERRORTYPE error =
+ OMX_AllocateBuffer(handle_, &buffer, output_port_, NULL,
+ output_port_definition_.nBufferSize);
+ SB_DCHECK(error == OMX_ErrorNone);
+ output_buffers_.push_back(buffer);
+ }
+
WaitForCommandCompletion();
- error = OMX_FillThisBuffer(handle_, output_buffer_);
- SB_DCHECK(error == OMX_ErrorNone);
+ output_port_enabled_ = true;
+
+ for (size_t i = 0; i < output_buffers_.size(); ++i) {
+ output_buffers_[i]->nFilledLen = 0;
+ OMX_ERRORTYPE error = OMX_FillThisBuffer(handle_, output_buffers_[i]);
+ SB_DCHECK(error == OMX_ErrorNone);
+ }
}
OMX_BUFFERHEADERTYPE* OpenMaxComponent::GetUnusedInputBuffer() {
for (;;) {
- ScopedLock scoped_lock(mutex_);
- if (!unused_buffers_.empty()) {
- OMX_BUFFERHEADERTYPE* buffer_header = unused_buffers_.back();
- unused_buffers_.pop_back();
- return buffer_header;
+ {
+ ScopedLock scoped_lock(mutex_);
+ if (!unused_input_buffers_.empty()) {
+ OMX_BUFFERHEADERTYPE* buffer_header = unused_input_buffers_.front();
+ unused_input_buffers_.pop();
+ return buffer_header;
+ }
}
SbThreadSleep(kSbTimeMillisecond);
}
@@ -312,13 +321,12 @@
OMX_ERRORTYPE OpenMaxComponent::OnEmptyBufferDone(
OMX_BUFFERHEADERTYPE* buffer) {
ScopedLock scoped_lock(mutex_);
- unused_buffers_.push_back(buffer);
+ unused_input_buffers_.push(buffer);
}
void OpenMaxComponent::OnFillBufferDone(OMX_BUFFERHEADERTYPE* buffer) {
ScopedLock scoped_lock(mutex_);
- SB_DCHECK(!output_buffer_filled_);
- output_buffer_filled_ = true;
+ filled_output_buffers_.push(buffer);
}
// static
diff --git a/src/starboard/raspi/shared/open_max/open_max_component.h b/src/starboard/raspi/shared/open_max/open_max_component.h
index 9085c1b..d9b5295 100644
--- a/src/starboard/raspi/shared/open_max/open_max_component.h
+++ b/src/starboard/raspi/shared/open_max/open_max_component.h
@@ -22,13 +22,14 @@
#include <interface/vcos/vcos.h>
#include <interface/vcos/vcos_logging.h>
#include <interface/vmcs_host/vchost.h>
+
+#include <queue>
#include <vector>
#include "starboard/condition_variable.h"
#include "starboard/log.h"
#include "starboard/mutex.h"
#include "starboard/shared/internal_only.h"
-#include "starboard/shared/starboard/player/video_frame_internal.h"
#include "starboard/time.h"
namespace starboard {
@@ -53,10 +54,8 @@
class OpenMaxComponent {
public:
- typedef starboard::shared::starboard::player::VideoFrame VideoFrame;
-
- explicit OpenMaxComponent(const char* name, size_t minimum_output_size = 0);
- ~OpenMaxComponent();
+ explicit OpenMaxComponent(const char* name);
+ virtual ~OpenMaxComponent();
void Start();
void Flush();
@@ -64,7 +63,8 @@
void WriteData(const void* data, size_t size, SbTime timestamp);
void WriteEOS();
- bool ReadVideoFrame(VideoFrame* frame);
+ OMX_BUFFERHEADERTYPE* PeekNextOutputBuffer();
+ void DropNextOutputBuffer();
template <typename ParamType>
void GetInputPortParam(ParamType* param) const {
@@ -94,8 +94,6 @@
}
private:
- typedef std::vector<OMX_BUFFERHEADERTYPE*> BufferHeaders;
-
struct EventDescription {
OMX_EVENTTYPE event;
OMX_U32 data1;
@@ -105,6 +103,13 @@
typedef std::vector<EventDescription> EventDescriptions;
+ virtual bool OnEnableInputPort(OMXParamPortDefinition* port_definition) {
+ return false;
+ }
+ virtual bool OnEnableOutputPort(OMXParamPortDefinition* port_definition) {
+ return false;
+ }
+
void SendCommand(OMX_COMMANDTYPE command, int param);
void WaitForCommandCompletion();
void SendCommandAndWaitForCompletion(OMX_COMMANDTYPE command, int param);
@@ -134,16 +139,18 @@
Mutex mutex_;
ConditionVariable condition_variable_;
- const size_t minimum_output_size_;
OMX_HANDLETYPE handle_;
int input_port_;
int output_port_;
bool output_setting_changed_;
EventDescriptions event_descriptions_;
- BufferHeaders unused_buffers_;
- OMX_BUFFERHEADERTYPE* output_buffer_;
+ std::vector<OMX_BUFFERHEADERTYPE*> input_buffers_;
+ std::queue<OMX_BUFFERHEADERTYPE*> unused_input_buffers_;
+ std::vector<OMX_BUFFERHEADERTYPE*> output_buffers_;
+ std::queue<OMX_BUFFERHEADERTYPE*> filled_output_buffers_;
+
OMXParamPortDefinition output_port_definition_;
- bool output_buffer_filled_;
+ bool output_port_enabled_;
};
} // namespace open_max
diff --git a/src/starboard/raspi/shared/open_max/open_max_video_decode_component.cc b/src/starboard/raspi/shared/open_max/open_max_video_decode_component.cc
new file mode 100644
index 0000000..0520c36
--- /dev/null
+++ b/src/starboard/raspi/shared/open_max/open_max_video_decode_component.cc
@@ -0,0 +1,165 @@
+// Copyright 2016 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "starboard/raspi/shared/open_max/open_max_video_decode_component.h"
+
+#include <algorithm>
+
+#include "starboard/configuration.h"
+
+namespace starboard {
+namespace raspi {
+namespace shared {
+namespace open_max {
+
+namespace {
+
+const char kVideoDecodeComponentName[] = "OMX.broadcom.video_decode";
+const size_t kResourcePoolSize = 12;
+const size_t kOMXOutputBufferCount = 4;
+const int kMaxFrameWidth = 1920;
+const int kMaxFrameHeight = 1088;
+const size_t kMaxVideoFrameSize = kMaxFrameWidth * kMaxFrameHeight * 3 / 2;
+
+} // namespace
+
+typedef OpenMaxVideoDecodeComponent::VideoFrame VideoFrame;
+
+VideoFrameResourcePool::VideoFrameResourcePool(size_t max_number_of_resources)
+ : max_number_of_resources_(max_number_of_resources),
+ number_of_resources_(0),
+ last_frame_height_(0) {}
+
+VideoFrameResourcePool::~VideoFrameResourcePool() {
+ for (ResourceMap::iterator iter = resource_map_.begin();
+ iter != resource_map_.end(); ++iter) {
+ while (!iter->second.empty()) {
+ delete iter->second.front();
+ iter->second.pop();
+ --number_of_resources_;
+ }
+ }
+ SB_DCHECK(number_of_resources_ == 0) << number_of_resources_;
+}
+
+DispmanxYUV420Resource* VideoFrameResourcePool::Alloc(int width,
+ int height,
+ int visible_width,
+ int visible_height) {
+ ScopedLock scoped_lock(mutex_);
+
+ last_frame_height_ = height;
+
+ ResourceMap::iterator iter = resource_map_.find(height);
+ if (iter != resource_map_.end() && !iter->second.empty()) {
+ DispmanxYUV420Resource* resource = iter->second.front();
+ iter->second.pop();
+ return resource;
+ }
+
+ if (number_of_resources_ >= max_number_of_resources_) {
+ return NULL;
+ }
+
+ ++number_of_resources_;
+ return new DispmanxYUV420Resource(width, height, visible_width,
+ visible_height);
+}
+
+void VideoFrameResourcePool::Free(DispmanxYUV420Resource* resource) {
+ ScopedLock scoped_lock(mutex_);
+ if (resource->height() != last_frame_height_) {
+ // The video has adapted, free the resource as it won't be reused any soon.
+ delete resource;
+ --number_of_resources_;
+ return;
+ }
+ resource_map_[resource->height()].push(resource);
+}
+
+// static
+void VideoFrameResourcePool::DisposeDispmanxYUV420Resource(
+ void* context,
+ void* dispmanx_resource) {
+ SB_DCHECK(context != NULL);
+ SB_DCHECK(dispmanx_resource != NULL);
+ VideoFrameResourcePool* pool =
+ reinterpret_cast<VideoFrameResourcePool*>(context);
+ pool->Free(reinterpret_cast<DispmanxYUV420Resource*>(dispmanx_resource));
+ pool->Release();
+}
+
+OpenMaxVideoDecodeComponent::OpenMaxVideoDecodeComponent()
+ : OpenMaxComponent(kVideoDecodeComponentName),
+ resource_pool_(new VideoFrameResourcePool(kResourcePoolSize)) {}
+
+scoped_refptr<VideoFrame> OpenMaxVideoDecodeComponent::ReadVideoFrame() {
+ if (OMX_BUFFERHEADERTYPE* buffer = PeekNextOutputBuffer()) {
+ if (scoped_refptr<VideoFrame> frame = CreateVideoFrame(buffer)) {
+ DropNextOutputBuffer();
+ return frame;
+ }
+ }
+ return NULL;
+}
+
+scoped_refptr<VideoFrame> OpenMaxVideoDecodeComponent::CreateVideoFrame(
+ OMX_BUFFERHEADERTYPE* buffer) {
+ scoped_refptr<VideoFrame> frame;
+ if (buffer->nFlags & OMX_BUFFERFLAG_EOS) {
+ frame = VideoFrame::CreateEOSFrame();
+ } else {
+ OMX_VIDEO_PORTDEFINITIONTYPE& video_definition =
+ output_port_definition_.format.video;
+ DispmanxYUV420Resource* resource = resource_pool_->Alloc(
+ video_definition.nStride, video_definition.nSliceHeight,
+ video_definition.nFrameWidth, video_definition.nFrameHeight);
+ if (!resource) {
+ return NULL;
+ }
+
+ resource->WriteData(buffer->pBuffer);
+
+ SbMediaTime timestamp = ((buffer->nTimeStamp.nHighPart * 0x100000000ull) +
+ buffer->nTimeStamp.nLowPart) *
+ kSbMediaTimeSecond / kSbTimeSecond;
+
+ resource_pool_->AddRef();
+ frame = new VideoFrame(
+ video_definition.nFrameWidth, video_definition.nFrameHeight, timestamp,
+ resource, resource_pool_,
+ &VideoFrameResourcePool::DisposeDispmanxYUV420Resource);
+ }
+ return frame;
+}
+
+bool OpenMaxVideoDecodeComponent::OnEnableOutputPort(
+ OMXParamPortDefinition* port_definition) {
+ SB_DCHECK(port_definition);
+
+ output_port_definition_ = *port_definition;
+ SB_DCHECK(port_definition->format.video.eColorFormat ==
+ OMX_COLOR_FormatYUV420PackedPlanar);
+ port_definition->format.video.eColorFormat =
+ OMX_COLOR_FormatYUV420PackedPlanar;
+ port_definition->nBufferCountActual = kOMXOutputBufferCount;
+ port_definition->nBufferSize =
+ std::max(port_definition->nBufferSize, kMaxVideoFrameSize);
+ return true;
+}
+
+} // namespace open_max
+} // namespace shared
+} // namespace raspi
+} // namespace starboard
diff --git a/src/starboard/raspi/shared/open_max/open_max_video_decode_component.h b/src/starboard/raspi/shared/open_max/open_max_video_decode_component.h
new file mode 100644
index 0000000..94b9cda
--- /dev/null
+++ b/src/starboard/raspi/shared/open_max/open_max_video_decode_component.h
@@ -0,0 +1,84 @@
+// Copyright 2016 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef STARBOARD_RASPI_SHARED_OPEN_MAX_OPEN_MAX_VIDEO_DECODE_COMPONENT_H_
+#define STARBOARD_RASPI_SHARED_OPEN_MAX_OPEN_MAX_VIDEO_DECODE_COMPONENT_H_
+
+#include <map>
+#include <queue>
+
+#include "starboard/common/ref_counted.h"
+#include "starboard/raspi/shared/dispmanx_util.h"
+#include "starboard/raspi/shared/open_max/open_max_component.h"
+
+namespace starboard {
+namespace raspi {
+namespace shared {
+namespace open_max {
+
+class VideoFrameResourcePool
+ : public RefCountedThreadSafe<VideoFrameResourcePool> {
+ public:
+ explicit VideoFrameResourcePool(size_t max_number_of_resources);
+ ~VideoFrameResourcePool();
+
+ DispmanxYUV420Resource* Alloc(int width,
+ int height,
+ int visible_width,
+ int visible_height);
+ void Free(DispmanxYUV420Resource* resource);
+
+ static void DisposeDispmanxYUV420Resource(void* context,
+ void* dispmanx_resource);
+
+ private:
+ typedef std::queue<DispmanxYUV420Resource*> ResourceQueue;
+ // Map frame height to resource handles.
+ typedef std::map<int, ResourceQueue> ResourceMap;
+
+ const size_t max_number_of_resources_;
+
+ Mutex mutex_;
+ size_t number_of_resources_;
+ int last_frame_height_;
+ ResourceMap resource_map_;
+};
+
+// Encapsulate a "OMX.broadcom.video_decode" component. Note that member
+// functions of this class is expected to be called from ANY threads as this
+// class works with the VideoDecoder filter, the OpenMAX component, and also
+// manages the disposition of Dispmanx resource.
+class OpenMaxVideoDecodeComponent : public OpenMaxComponent {
+ public:
+ typedef starboard::shared::starboard::player::VideoFrame VideoFrame;
+
+ OpenMaxVideoDecodeComponent();
+
+ scoped_refptr<VideoFrame> ReadVideoFrame();
+
+ private:
+ scoped_refptr<VideoFrame> CreateVideoFrame(OMX_BUFFERHEADERTYPE* buffer);
+
+ bool OnEnableOutputPort(OMXParamPortDefinition* port_definition) SB_OVERRIDE;
+
+ scoped_refptr<VideoFrameResourcePool> resource_pool_;
+ OMXParamPortDefinition output_port_definition_;
+};
+
+} // namespace open_max
+} // namespace shared
+} // namespace raspi
+} // namespace starboard
+
+#endif // STARBOARD_RASPI_SHARED_OPEN_MAX_OPEN_MAX_VIDEO_DECODE_COMPONENT_H_
diff --git a/src/starboard/raspi/shared/open_max/video_decoder.cc b/src/starboard/raspi/shared/open_max/video_decoder.cc
index 702a9f8..a238db7 100644
--- a/src/starboard/raspi/shared/open_max/video_decoder.cc
+++ b/src/starboard/raspi/shared/open_max/video_decoder.cc
@@ -23,17 +23,8 @@
using starboard::shared::starboard::player::VideoFrame;
-namespace {
-
-const char kVideoDecodeComponentName[] = "OMX.broadcom.video_decode";
-const size_t kMaxVideoFrameSize = 1920 * 1088 * 3 / 2;
-
-} // namespace
-
VideoDecoder::VideoDecoder(SbMediaVideoCodec video_codec)
- : component_(kVideoDecodeComponentName, kMaxVideoFrameSize),
- host_(NULL),
- stream_ended_(false) {
+ : host_(NULL), stream_ended_(false) {
SB_DCHECK(video_codec == kSbMediaVideoCodecH264);
OMXVideoParamPortFormat port_format;
@@ -61,11 +52,11 @@
}
component_.WriteData(input_buffer.data(), input_buffer.size(),
input_buffer.pts() * kSbTimeSecond / kSbMediaTimeSecond);
-
- VideoFrame frame;
- if (component_.ReadVideoFrame(&frame)) {
- host_->OnDecoderStatusUpdate(kNeedMoreInput, &frame);
+ if (scoped_refptr<VideoFrame> frame = component_.ReadVideoFrame()) {
+ host_->OnDecoderStatusUpdate(kNeedMoreInput, frame);
} else {
+ // Call the callback with NULL frame to ensure that the host know that more
+ // data is expected.
host_->OnDecoderStatusUpdate(kNeedMoreInput, NULL);
}
}
diff --git a/src/starboard/raspi/shared/open_max/video_decoder.h b/src/starboard/raspi/shared/open_max/video_decoder.h
index 92850da..de684af 100644
--- a/src/starboard/raspi/shared/open_max/video_decoder.h
+++ b/src/starboard/raspi/shared/open_max/video_decoder.h
@@ -16,7 +16,7 @@
#define STARBOARD_RASPI_SHARED_OPEN_MAX_VIDEO_DECODER_H_
#include "starboard/media.h"
-#include "starboard/raspi/shared/open_max/open_max_component.h"
+#include "starboard/raspi/shared/open_max/open_max_video_decode_component.h"
#include "starboard/shared/internal_only.h"
#include "starboard/shared/starboard/player/filter/video_decoder_internal.h"
@@ -39,7 +39,7 @@
void Reset() SB_OVERRIDE;
private:
- OpenMaxComponent component_;
+ OpenMaxVideoDecodeComponent component_;
// These variables will be initialized inside ctor or SetHost() and will not
// be changed during the life time of this class.
diff --git a/src/starboard/shared/directfb/blitter_destroy_swap_chain.cc b/src/starboard/shared/directfb/blitter_destroy_swap_chain.cc
index ba9d317..2f9505b 100644
--- a/src/starboard/shared/directfb/blitter_destroy_swap_chain.cc
+++ b/src/starboard/shared/directfb/blitter_destroy_swap_chain.cc
@@ -26,5 +26,7 @@
swap_chain->render_target.surface->Release(swap_chain->render_target.surface);
+ delete swap_chain;
+
return true;
}
diff --git a/src/starboard/shared/ffmpeg/ffmpeg_video_decoder.cc b/src/starboard/shared/ffmpeg/ffmpeg_video_decoder.cc
index 7b9efed..2e05ee8 100644
--- a/src/starboard/shared/ffmpeg/ffmpeg_video_decoder.cc
+++ b/src/starboard/shared/ffmpeg/ffmpeg_video_decoder.cc
@@ -197,8 +197,7 @@
packet.pts = 0;
} while (DecodePacket(&packet));
- VideoFrame frame = VideoFrame::CreateEOSFrame();
- host_->OnDecoderStatusUpdate(kBufferFull, &frame);
+ host_->OnDecoderStatusUpdate(kBufferFull, VideoFrame::CreateEOSFrame());
}
}
}
@@ -223,11 +222,11 @@
int pitch = AlignUp(av_frame_->width, kAlignment * 2);
- VideoFrame frame = VideoFrame::CreateYV12Frame(
+ scoped_refptr<VideoFrame> frame = VideoFrame::CreateYV12Frame(
av_frame_->width, av_frame_->height, pitch,
codec_context_->reordered_opaque, av_frame_->data[0], av_frame_->data[1],
av_frame_->data[2]);
- host_->OnDecoderStatusUpdate(kBufferFull, &frame);
+ host_->OnDecoderStatusUpdate(kBufferFull, frame);
return true;
}
diff --git a/src/starboard/shared/posix/socket_receive_from.cc b/src/starboard/shared/posix/socket_receive_from.cc
index c4819b6..ca0cb04 100644
--- a/src/starboard/shared/posix/socket_receive_from.cc
+++ b/src/starboard/shared/posix/socket_receive_from.cc
@@ -27,11 +27,7 @@
char* out_data,
int data_size,
SbSocketAddress* out_source) {
-#if defined(MSG_NOSIGNAL)
- const int kRecvFlags = MSG_NOSIGNAL;
-#else
const int kRecvFlags = 0;
-#endif
if (!SbSocketIsValid(socket)) {
errno = EBADF;
diff --git a/src/starboard/shared/signal/crash_signals.cc b/src/starboard/shared/signal/crash_signals.cc
index 0d74011..78b3ab2 100644
--- a/src/starboard/shared/signal/crash_signals.cc
+++ b/src/starboard/shared/signal/crash_signals.cc
@@ -32,7 +32,7 @@
};
const int kStopSignalsToTrap[] = {
- SIGTERM, SIGINT, SIGHUP,
+ SIGHUP,
};
void Crash(int signal_id) {
diff --git a/src/starboard/shared/signal/crash_signals_sigaction.cc b/src/starboard/shared/signal/crash_signals_sigaction.cc
index 5273ab1..da318a8 100644
--- a/src/starboard/shared/signal/crash_signals_sigaction.cc
+++ b/src/starboard/shared/signal/crash_signals_sigaction.cc
@@ -32,7 +32,7 @@
};
const int kStopSignalsToTrap[] = {
- SIGTERM, SIGINT, SIGHUP,
+ SIGHUP,
};
void SetSignalHandler(int signal_id, SignalHandlerFunction handler) {
diff --git a/src/starboard/shared/signal/suspend_signals.cc b/src/starboard/shared/signal/suspend_signals.cc
index 6bb42d8..4048a3b 100644
--- a/src/starboard/shared/signal/suspend_signals.cc
+++ b/src/starboard/shared/signal/suspend_signals.cc
@@ -15,6 +15,7 @@
#include "starboard/shared/signal/suspend_signals.h"
#include <signal.h>
+#include <sys/socket.h>
#include "starboard/configuration.h"
#include "starboard/log.h"
@@ -71,19 +72,34 @@
} // namespace
+#if !defined(MSG_NOSIGNAL) && defined(SO_NOSIGPIPE)
+// See "#if !defined(MSG_NOSIGNAL)" below.
+// OS X, which we do not build for today, has another mechanism which
+// should be used.
+#error On this platform, please use SO_NOSIGPIPE and leave the SIGPIPE \
+ handler at default.
+#endif
+
void InstallSuspendSignalHandlers() {
SetSignalHandler(SIGTSTP, &Suspend);
UnblockSignal(SIGTSTP);
SetSignalHandler(SIGCONT, &Resume);
- // We might receive SIGPIPE after resuming. We should not terminate.
+#if !defined(MSG_NOSIGNAL)
+ // By default in POSIX, sending to a closed socket causes a SIGPIPE
+ // If we cannot disable that behavior, we must ignore SIGPIPE.
+ // Ignoring SIGPIPE means cases that use pipes to redirect the stdio
+ // log messages may behave in surprising ways, so it's not desirable.
SetSignalHandler(SIGPIPE, &Ignore);
+#endif
}
void UninstallSuspendSignalHandlers() {
SetSignalHandler(SIGCONT, SIG_DFL);
SetSignalHandler(SIGTSTP, SIG_DFL);
+#if !defined(MSG_NOSIGNAL)
SetSignalHandler(SIGPIPE, SIG_DFL);
+#endif
}
} // namespace signal
diff --git a/src/starboard/shared/starboard/application.cc b/src/starboard/shared/starboard/application.cc
index 96efbdb..4f2e850 100644
--- a/src/starboard/shared/starboard/application.cc
+++ b/src/starboard/shared/starboard/application.cc
@@ -130,7 +130,7 @@
#if SB_HAS(PLAYER) && SB_IS(PLAYER_PUNCHED_OUT)
void Application::HandleFrame(SbPlayer player,
- const VideoFrame& frame,
+ const scoped_refptr<VideoFrame>& frame,
int x,
int y,
int width,
diff --git a/src/starboard/shared/starboard/application.h b/src/starboard/shared/starboard/application.h
index f8609ce..4387bed 100644
--- a/src/starboard/shared/starboard/application.h
+++ b/src/starboard/shared/starboard/application.h
@@ -202,7 +202,7 @@
// used when the application needs to composite video frames with punch-out
// video manually (should be rare). Will be called from an external thread.
void HandleFrame(SbPlayer player,
- const VideoFrame& frame,
+ const scoped_refptr<VideoFrame>& frame,
int x,
int y,
int width,
@@ -224,7 +224,7 @@
// Subclasses may override this method to accept video frames from the media
// system. Will be called from an external thread.
virtual void AcceptFrame(SbPlayer player,
- const VideoFrame& frame,
+ const scoped_refptr<VideoFrame>& frame,
int x,
int y,
int width,
diff --git a/src/starboard/shared/starboard/blitter_blit_rect_to_rect_tiled.cc b/src/starboard/shared/starboard/blitter_blit_rect_to_rect_tiled.cc
index 3317806..8648663 100644
--- a/src/starboard/shared/starboard/blitter_blit_rect_to_rect_tiled.cc
+++ b/src/starboard/shared/starboard/blitter_blit_rect_to_rect_tiled.cc
@@ -248,9 +248,11 @@
}
}
- return SbBlitterBlitRectsToRects(context, source_surface, src_rects,
- dst_rects, num_tiles);
+ bool result = SbBlitterBlitRectsToRects(context, source_surface, src_rects,
+ dst_rects, num_tiles);
delete[] src_rects;
delete[] dst_rects;
+
+ return result;
}
diff --git a/src/starboard/shared/starboard/file_storage/storage_internal.h b/src/starboard/shared/starboard/file_storage/storage_internal.h
index ea322b8..6bb3362 100644
--- a/src/starboard/shared/starboard/file_storage/storage_internal.h
+++ b/src/starboard/shared/starboard/file_storage/storage_internal.h
@@ -33,9 +33,9 @@
namespace shared {
namespace starboard {
// Gets the path to the storage file for the given user.
-SB_C_INLINE bool GetUserStorageFilePath(SbUser user,
- char* out_path,
- int path_size) {
+static SB_C_INLINE bool GetUserStorageFilePath(SbUser user,
+ char* out_path,
+ int path_size) {
bool success = SbUserGetProperty(user, kSbUserPropertyHomeDirectory, out_path,
path_size);
if (!success) {
diff --git a/src/starboard/shared/starboard/localized_strings.cc b/src/starboard/shared/starboard/localized_strings.cc
index 2639c53..0f802e6 100644
--- a/src/starboard/shared/starboard/localized_strings.cc
+++ b/src/starboard/shared/starboard/localized_strings.cc
@@ -116,7 +116,7 @@
return false;
}
SB_DCHECK(file_contents.length() > 0);
- SB_DCHECK(file_contents.back() == '\n');
+ SB_DCHECK(file_contents[file_contents.length() - 1] == '\n');
// Each line of the file corresponds to one message (key/value).
size_t pos = 0;
diff --git a/src/starboard/shared/starboard/player/filter/filter_based_player_worker_handler.cc b/src/starboard/shared/starboard/player/filter/filter_based_player_worker_handler.cc
index 54477cf..b73cbb2 100644
--- a/src/starboard/shared/starboard/player/filter/filter_based_player_worker_handler.cc
+++ b/src/starboard/shared/starboard/player/filter/filter_based_player_worker_handler.cc
@@ -210,7 +210,7 @@
(*player_worker_.*update_player_state_cb_)(kSbPlayerStateEndOfStream);
}
- const VideoFrame& frame =
+ scoped_refptr<VideoFrame> frame =
video_renderer_->GetCurrentFrame(audio_renderer_->GetCurrentTime());
#if SB_IS(PLAYER_PUNCHED_OUT)
@@ -230,8 +230,8 @@
#if SB_IS(PLAYER_PUNCHED_OUT)
// Clear the video frame as we terminate.
- shared::starboard::Application::Get()->HandleFrame(player_, VideoFrame(), 0,
- 0, 0, 0);
+ shared::starboard::Application::Get()->HandleFrame(
+ player_, VideoFrame::CreateEOSFrame(), 0, 0, 0, 0);
#endif // SB_IS(PLAYER_PUNCHED_OUT)
}
diff --git a/src/starboard/shared/starboard/player/filter/video_decoder_internal.h b/src/starboard/shared/starboard/player/filter/video_decoder_internal.h
index fd32c9f..e55c685 100644
--- a/src/starboard/shared/starboard/player/filter/video_decoder_internal.h
+++ b/src/starboard/shared/starboard/player/filter/video_decoder_internal.h
@@ -37,7 +37,9 @@
// user should only call WriteInputFrame() when |status| is kNeedMoreInput
// or when the instance is just created. Also note that calling Reset() or
// dtor from this callback will result in deadlock.
- virtual void OnDecoderStatusUpdate(Status status, VideoFrame* frame) = 0;
+ virtual void OnDecoderStatusUpdate(
+ Status status,
+ const scoped_refptr<VideoFrame>& frame) = 0;
protected:
~Host() {}
diff --git a/src/starboard/shared/starboard/player/filter/video_renderer_internal.cc b/src/starboard/shared/starboard/player/filter/video_renderer_internal.cc
index 65ee800..35b6bf0 100644
--- a/src/starboard/shared/starboard/player/filter/video_renderer_internal.cc
+++ b/src/starboard/shared/starboard/player/filter/video_renderer_internal.cc
@@ -79,7 +79,8 @@
frames_.clear();
}
-const VideoFrame& VideoRenderer::GetCurrentFrame(SbMediaTime media_time) {
+scoped_refptr<VideoFrame> VideoRenderer::GetCurrentFrame(
+ SbMediaTime media_time) {
SB_DCHECK(thread_checker_.CalledOnValidThread());
if (frames_.empty()) {
@@ -87,7 +88,7 @@
}
// Remove any frames with timestamps earlier than |media_time|, but always
// keep at least one of the frames.
- while (frames_.size() > 1 && frames_.front().pts() < media_time) {
+ while (frames_.size() > 1 && frames_.front()->pts() < media_time) {
frames_.pop_front();
}
@@ -101,6 +102,7 @@
bool VideoRenderer::CanAcceptMoreData() const {
SB_DCHECK(thread_checker_.CalledOnValidThread());
+ ScopedLock lock(mutex_);
return frames_.size() < kMaxCachedFrames && !end_of_stream_written_ &&
need_more_input_;
}
@@ -110,8 +112,9 @@
return seeking_;
}
-void VideoRenderer::OnDecoderStatusUpdate(VideoDecoder::Status status,
- VideoFrame* frame) {
+void VideoRenderer::OnDecoderStatusUpdate(
+ VideoDecoder::Status status,
+ const scoped_refptr<VideoFrame>& frame) {
ScopedLock lock(mutex_);
if (frame) {
@@ -124,7 +127,7 @@
}
}
if (!frame_too_early) {
- frames_.push_back(*frame);
+ frames_.push_back(frame);
}
if (seeking_ && frames_.size() >= kPrerollFrames) {
diff --git a/src/starboard/shared/starboard/player/filter/video_renderer_internal.h b/src/starboard/shared/starboard/player/filter/video_renderer_internal.h
index 8450e59..6cc4cad 100644
--- a/src/starboard/shared/starboard/player/filter/video_renderer_internal.h
+++ b/src/starboard/shared/starboard/player/filter/video_renderer_internal.h
@@ -44,7 +44,7 @@
void Seek(SbMediaTime seek_to_pts);
- const VideoFrame& GetCurrentFrame(SbMediaTime media_time);
+ scoped_refptr<VideoFrame> GetCurrentFrame(SbMediaTime media_time);
bool IsEndOfStreamWritten() const { return end_of_stream_written_; }
bool IsEndOfStreamPlayed() const;
@@ -52,7 +52,7 @@
bool IsSeekingInProgress() const;
private:
- typedef std::list<VideoFrame> Frames;
+ typedef std::list<scoped_refptr<VideoFrame> > Frames;
// Preroll considered finished after either kPrerollFrames is cached or EOS
// is reached.
@@ -65,7 +65,8 @@
// VideoDecoder::Host method.
void OnDecoderStatusUpdate(VideoDecoder::Status status,
- VideoFrame* frame) SB_OVERRIDE;
+ const scoped_refptr<VideoFrame>& frame)
+ SB_OVERRIDE;
ThreadChecker thread_checker_;
::starboard::Mutex mutex_;
@@ -77,7 +78,7 @@
// should still display the last frame it is rendering. This frame will be
// kept inside |seeking_frame_|. It is an empty/black frame before the video
// is started.
- VideoFrame seeking_frame_;
+ scoped_refptr<VideoFrame> seeking_frame_;
SbMediaTime seeking_to_pts_;
bool end_of_stream_written_;
diff --git a/src/starboard/shared/starboard/player/video_frame_internal.cc b/src/starboard/shared/starboard/player/video_frame_internal.cc
index 793066d..7bee2c4 100644
--- a/src/starboard/shared/starboard/player/video_frame_internal.cc
+++ b/src/starboard/shared/starboard/player/video_frame_internal.cc
@@ -73,53 +73,76 @@
} // namespace
-VideoFrame::VideoFrame(const VideoFrame& that) {
- *this = that;
+VideoFrame::VideoFrame() {
+ InitializeToInvalidFrame();
}
-VideoFrame& VideoFrame::operator=(const VideoFrame& that) {
- this->format_ = that.format_;
+VideoFrame::VideoFrame(int width,
+ int height,
+ SbMediaTime pts,
+ void* native_texture,
+ void* native_texture_context,
+ FreeNativeTextureFunc free_native_texture_func) {
+ SB_DCHECK(native_texture != NULL);
+ SB_DCHECK(free_native_texture_func != NULL);
- this->pts_ = that.pts_;
- this->planes_ = that.planes_;
- this->pixel_buffer_ = that.pixel_buffer_;
+ InitializeToInvalidFrame();
- for (int i = 0; i < GetPlaneCount(); ++i) {
- const uint8_t* data = that.GetPlane(i).data;
- const uint8_t* base = &that.pixel_buffer_[0];
- ptrdiff_t offset = data - base;
- SB_DCHECK(offset >= 0);
- SB_DCHECK(offset < static_cast<ptrdiff_t>(that.pixel_buffer_.size()));
- planes_[i].data = &pixel_buffer_[0] + offset;
+ format_ = kNativeTexture;
+ width_ = width;
+ height_ = height;
+ pts_ = pts;
+ native_texture_ = native_texture;
+ native_texture_context_ = native_texture_context;
+ free_native_texture_func_ = free_native_texture_func;
+}
+
+VideoFrame::~VideoFrame() {
+ if (format_ == kNativeTexture) {
+ free_native_texture_func_(native_texture_context_, native_texture_);
}
+}
- return *this;
+int VideoFrame::GetPlaneCount() const {
+ SB_DCHECK(format_ != kInvalid);
+ SB_DCHECK(format_ != kNativeTexture);
+
+ return static_cast<int>(planes_.size());
}
const VideoFrame::Plane& VideoFrame::GetPlane(int index) const {
+ SB_DCHECK(format_ != kInvalid);
+ SB_DCHECK(format_ != kNativeTexture);
SB_DCHECK(index >= 0 && index < GetPlaneCount()) << "Invalid index: "
<< index;
return planes_[index];
}
-VideoFrame VideoFrame::ConvertTo(Format target_format) const {
+void* VideoFrame::native_texture() const {
+ SB_DCHECK(format_ == kNativeTexture);
+ return native_texture_;
+}
+
+scoped_refptr<VideoFrame> VideoFrame::ConvertTo(Format target_format) const {
SB_DCHECK(format_ == kYV12);
SB_DCHECK(target_format == kBGRA32);
EnsureYUVToRGBLookupTableInitialized();
- VideoFrame target_frame;
+ scoped_refptr<VideoFrame> target_frame(new VideoFrame);
- target_frame.format_ = target_format;
- target_frame.pts_ = pts_;
- target_frame.pixel_buffer_.resize(width() * height() * 4);
- target_frame.planes_.push_back(
- Plane(width(), height(), width() * 4, &target_frame.pixel_buffer_[0]));
+ target_frame->format_ = target_format;
+ target_frame->width_ = width();
+ target_frame->height_ = height();
+ target_frame->pts_ = pts_;
+ target_frame->pixel_buffer_.reset(new uint8_t[width() * height() * 4]);
+ target_frame->planes_.push_back(
+ Plane(width(), height(), width() * 4, target_frame->pixel_buffer_.get()));
const uint8_t* y_data = GetPlane(0).data;
const uint8_t* u_data = GetPlane(1).data;
const uint8_t* v_data = GetPlane(2).data;
- uint8_t* bgra_data = &target_frame.pixel_buffer_[0];
+ uint8_t* bgra_data = target_frame->pixel_buffer_.get();
int height = this->height();
int width = this->width();
@@ -158,21 +181,23 @@
}
// static
-VideoFrame VideoFrame::CreateEOSFrame() {
- return VideoFrame();
+scoped_refptr<VideoFrame> VideoFrame::CreateEOSFrame() {
+ return new VideoFrame;
}
// static
-VideoFrame VideoFrame::CreateYV12Frame(int width,
- int height,
- int pitch_in_bytes,
- SbMediaTime pts,
- const uint8_t* y,
- const uint8_t* u,
- const uint8_t* v) {
- VideoFrame frame;
- frame.format_ = kYV12;
- frame.pts_ = pts;
+scoped_refptr<VideoFrame> VideoFrame::CreateYV12Frame(int width,
+ int height,
+ int pitch_in_bytes,
+ SbMediaTime pts,
+ const uint8_t* y,
+ const uint8_t* u,
+ const uint8_t* v) {
+ scoped_refptr<VideoFrame> frame(new VideoFrame);
+ frame->format_ = kYV12;
+ frame->width_ = width;
+ frame->height_ = height;
+ frame->pts_ = pts;
// U/V planes generally have half resolution of the Y plane. However, in the
// extreme case that any dimension of Y plane is odd, we want to have an
@@ -183,26 +208,38 @@
int y_plane_size_in_bytes = height * pitch_in_bytes;
int uv_plane_size_in_bytes = uv_height * uv_pitch_in_bytes;
- frame.pixel_buffer_.reserve(y_plane_size_in_bytes +
- uv_plane_size_in_bytes * 2);
- frame.pixel_buffer_.assign(y, y + y_plane_size_in_bytes);
- frame.pixel_buffer_.insert(frame.pixel_buffer_.end(), u,
- u + uv_plane_size_in_bytes);
- frame.pixel_buffer_.insert(frame.pixel_buffer_.end(), v,
- v + uv_plane_size_in_bytes);
+ frame->pixel_buffer_.reset(
+ new uint8_t[y_plane_size_in_bytes + uv_plane_size_in_bytes * 2]);
+ SbMemoryCopy(frame->pixel_buffer_.get(), y, y_plane_size_in_bytes);
+ SbMemoryCopy(frame->pixel_buffer_.get() + y_plane_size_in_bytes, u,
+ uv_plane_size_in_bytes);
+ SbMemoryCopy(frame->pixel_buffer_.get() + y_plane_size_in_bytes +
+ uv_plane_size_in_bytes,
+ v, uv_plane_size_in_bytes);
- frame.planes_.push_back(
- Plane(width, height, pitch_in_bytes, &frame.pixel_buffer_[0]));
- frame.planes_.push_back(
+ frame->planes_.push_back(
+ Plane(width, height, pitch_in_bytes, frame->pixel_buffer_.get()));
+ frame->planes_.push_back(
Plane(uv_width, uv_height, uv_pitch_in_bytes,
- &frame.pixel_buffer_[0] + y_plane_size_in_bytes));
- frame.planes_.push_back(Plane(uv_width, uv_height, uv_pitch_in_bytes,
- &frame.pixel_buffer_[0] +
- y_plane_size_in_bytes +
- uv_plane_size_in_bytes));
+ frame->pixel_buffer_.get() + y_plane_size_in_bytes));
+ frame->planes_.push_back(Plane(uv_width, uv_height, uv_pitch_in_bytes,
+ frame->pixel_buffer_.get() +
+ y_plane_size_in_bytes +
+ uv_plane_size_in_bytes));
return frame;
}
+void VideoFrame::InitializeToInvalidFrame() {
+ format_ = kInvalid;
+ width_ = 0;
+ height_ = 0;
+
+ pts_ = 0;
+ native_texture_ = NULL;
+ native_texture_context_ = NULL;
+ free_native_texture_func_ = NULL;
+}
+
} // namespace player
} // namespace starboard
} // namespace shared
diff --git a/src/starboard/shared/starboard/player/video_frame_internal.h b/src/starboard/shared/starboard/player/video_frame_internal.h
index 745ec31..c956e90 100644
--- a/src/starboard/shared/starboard/player/video_frame_internal.h
+++ b/src/starboard/shared/starboard/player/video_frame_internal.h
@@ -17,6 +17,9 @@
#include <vector>
+#include "starboard/common/ref_counted.h"
+#include "starboard/common/scoped_ptr.h"
+#include "starboard/configuration.h"
#include "starboard/media.h"
#include "starboard/shared/internal_only.h"
@@ -26,10 +29,12 @@
namespace player {
// A video frame produced by a video decoder.
-class VideoFrame {
+class VideoFrame : public RefCountedThreadSafe<VideoFrame> {
public:
+ typedef void (*FreeNativeTextureFunc)(void* context, void* textue);
+
enum Format {
- kInvalid,
+ kInvalid, // A VideoFrame in this format can be used to indicate EOS.
// This is the native format supported by XComposite (PictStandardARGB32
// with bytes swapped). Remove this once we are able to pass out frames
// as YV12 textures.
@@ -50,37 +55,55 @@
const uint8_t* data;
};
- VideoFrame() : format_(kInvalid) {}
- VideoFrame(const VideoFrame& that);
-
- VideoFrame& operator=(const VideoFrame& that);
+ VideoFrame(); // Create an EOS frame.
+ VideoFrame(int width,
+ int height,
+ SbMediaTime pts,
+ void* native_texture,
+ void* native_texture_context,
+ FreeNativeTextureFunc free_native_texture_func);
+ ~VideoFrame();
Format format() const { return format_; }
- int width() const { return GetPlaneCount() == 0 ? 0 : GetPlane(0).width; }
- int height() const { return GetPlaneCount() == 0 ? 0 : GetPlane(0).height; }
-
bool IsEndOfStream() const { return format_ == kInvalid; }
SbMediaTime pts() const { return pts_; }
- int GetPlaneCount() const { return static_cast<int>(planes_.size()); }
+ int width() const { return width_; }
+ int height() const { return height_; }
+
+ int GetPlaneCount() const;
const Plane& GetPlane(int index) const;
- VideoFrame ConvertTo(Format target_format) const;
+ void* native_texture() const;
- static VideoFrame CreateEOSFrame();
- static VideoFrame CreateYV12Frame(int width,
- int height,
- int pitch_in_bytes,
- SbMediaTime pts,
- const uint8_t* y,
- const uint8_t* u,
- const uint8_t* v);
+ scoped_refptr<VideoFrame> ConvertTo(Format target_format) const;
+
+ static scoped_refptr<VideoFrame> CreateEOSFrame();
+ static scoped_refptr<VideoFrame> CreateYV12Frame(int width,
+ int height,
+ int pitch_in_bytes,
+ SbMediaTime pts,
+ const uint8_t* y,
+ const uint8_t* u,
+ const uint8_t* v);
private:
- Format format_;
+ void InitializeToInvalidFrame();
+ Format format_;
+ int width_;
+ int height_;
SbMediaTime pts_;
+
+ // The following two variables are valid when the frame contains pixel data.
std::vector<Plane> planes_;
- std::vector<uint8_t> pixel_buffer_;
+ scoped_array<uint8_t> pixel_buffer_;
+
+ // The following three variables are valid when |format_| is `kNativeTexture`.
+ void* native_texture_;
+ void* native_texture_context_;
+ FreeNativeTextureFunc free_native_texture_func_;
+
+ SB_DISALLOW_COPY_AND_ASSIGN(VideoFrame);
};
} // namespace player
diff --git a/src/starboard/shared/x11/application_x11.cc b/src/starboard/shared/x11/application_x11.cc
index 1457e73..797c807 100644
--- a/src/starboard/shared/x11/application_x11.cc
+++ b/src/starboard/shared/x11/application_x11.cc
@@ -679,7 +679,7 @@
ScopedLock lock(frame_mutex_);
if (frame_written_) {
// Clear the old frame, now that we are done with it.
- frame_infos_[frame_read_index_].frame = VideoFrame();
+ frame_infos_[frame_read_index_].frame = NULL;
// Increment the index to the next frame, which has been written.
frame_read_index_ = (frame_read_index_ + 1) % kNumFrames;
@@ -692,12 +692,12 @@
}
FrameInfo& frame_info = frame_infos_[frame_read_index_];
- if (!frame_info.frame.IsEndOfStream() &&
- frame_info.frame.format() != VideoFrame::kBGRA32) {
- frame_info.frame = frame_info.frame.ConvertTo(VideoFrame::kBGRA32);
+ if (frame_info.frame && !frame_info.frame->IsEndOfStream() &&
+ frame_info.frame->format() != VideoFrame::kBGRA32) {
+ frame_info.frame = frame_info.frame->ConvertTo(VideoFrame::kBGRA32);
}
window->Composite(frame_info.x, frame_info.y, frame_info.width,
- frame_info.height, &frame_info.frame);
+ frame_info.height, frame_info.frame);
}
}
composite_event_id_ =
@@ -705,7 +705,7 @@
}
void ApplicationX11::AcceptFrame(SbPlayer player,
- const VideoFrame& frame,
+ const scoped_refptr<VideoFrame>& frame,
int x,
int y,
int width,
diff --git a/src/starboard/shared/x11/application_x11.h b/src/starboard/shared/x11/application_x11.h
index 8bd9940..efe2a24 100644
--- a/src/starboard/shared/x11/application_x11.h
+++ b/src/starboard/shared/x11/application_x11.h
@@ -49,7 +49,7 @@
protected:
void AcceptFrame(SbPlayer player,
- const shared::starboard::player::VideoFrame& frame,
+ const scoped_refptr<VideoFrame>& frame,
int x,
int y,
int width,
@@ -71,7 +71,7 @@
#if SB_IS(PLAYER_PUNCHED_OUT)
struct FrameInfo {
- shared::starboard::player::VideoFrame frame;
+ scoped_refptr<VideoFrame> frame;
int x;
int y;
int width;
diff --git a/src/starboard/shared/x11/window_internal.cc b/src/starboard/shared/x11/window_internal.cc
index b17082a..70daeb3 100644
--- a/src/starboard/shared/x11/window_internal.cc
+++ b/src/starboard/shared/x11/window_internal.cc
@@ -30,8 +30,6 @@
#include <X11/extensions/Xrender.h>
#endif // SB_IS(PLAYER_PUNCHED_OUT)
-using starboard::shared::starboard::player::VideoFrame;
-
namespace {
const int kWindowWidth = 1920;
@@ -148,11 +146,12 @@
}
#if SB_IS(PLAYER_PUNCHED_OUT)
-void SbWindowPrivate::Composite(int bounds_x,
- int bounds_y,
- int bounds_width,
- int bounds_height,
- VideoFrame* frame) {
+void SbWindowPrivate::Composite(
+ int bounds_x,
+ int bounds_y,
+ int bounds_width,
+ int bounds_height,
+ const starboard::scoped_refptr<VideoFrame>& frame) {
XSynchronize(display, True);
XWindowAttributes window_attributes;
XGetWindowAttributes(display, window, &window_attributes);
diff --git a/src/starboard/shared/x11/window_internal.h b/src/starboard/shared/x11/window_internal.h
index 7c55cb3..e96ffdc 100644
--- a/src/starboard/shared/x11/window_internal.h
+++ b/src/starboard/shared/x11/window_internal.h
@@ -33,6 +33,8 @@
Window window;
#if SB_IS(PLAYER_PUNCHED_OUT)
+ typedef ::starboard::shared::starboard::player::VideoFrame VideoFrame;
+
// Composites graphics and the given video frame video for this window. In
// PLAYER_PUNCHED_OUT mode, this is the only way any graphics or video is
// presented in the window. The video frame will be rendered according to
@@ -41,7 +43,7 @@
int bounds_y,
int bounds_width,
int bounds_height,
- ::starboard::shared::starboard::player::VideoFrame* frame);
+ const starboard::scoped_refptr<VideoFrame>& frame);
// The cached XRender Picture that represents the window that is the
// destination of the composition.
diff --git a/src/starboard/thread.h b/src/starboard/thread.h
index d2138e0..f642f28 100644
--- a/src/starboard/thread.h
+++ b/src/starboard/thread.h
@@ -255,7 +255,7 @@
// Returns whether |thread| is the current thread.
//
// |thread|: The thread to check.
-SB_C_INLINE bool SbThreadIsCurrent(SbThread thread) {
+static SB_C_INLINE bool SbThreadIsCurrent(SbThread thread) {
return SbThreadGetCurrent() == thread;
}
diff --git a/src/third_party/glm/glm/detail/setup.hpp b/src/third_party/glm/glm/detail/setup.hpp
index 0d524b2..349dbfa 100644
--- a/src/third_party/glm/glm/detail/setup.hpp
+++ b/src/third_party/glm/glm/detail/setup.hpp
@@ -305,7 +305,9 @@
#endif
// N1988
-#if GLM_LANG & GLM_LANG_CXX11_FLAG
+#if defined(STARBOARD)
+# define GLM_HAS_EXTENDED_INTEGER_TYPE 0
+#elif GLM_LANG & GLM_LANG_CXX11_FLAG
# define GLM_HAS_EXTENDED_INTEGER_TYPE 1
#else
# define GLM_HAS_EXTENDED_INTEGER_TYPE (\
diff --git a/src/third_party/glm/glm/detail/type_int.hpp b/src/third_party/glm/glm/detail/type_int.hpp
index 764a32c..f37a40a 100644
--- a/src/third_party/glm/glm/detail/type_int.hpp
+++ b/src/third_party/glm/glm/detail/type_int.hpp
@@ -4,6 +4,11 @@
#pragma once
#include "setup.hpp"
+
+#if defined(STARBOARD)
+#include "starboard/types.h"
+
+#else // defined(STARBOARD)
#if GLM_HAS_MAKE_SIGNED
# include <type_traits>
#endif
@@ -11,11 +16,22 @@
#if GLM_HAS_EXTENDED_INTEGER_TYPE
# include <cstdint>
#endif
+#endif // defined(STARBOARD)
namespace glm{
namespace detail
{
-# if GLM_HAS_EXTENDED_INTEGER_TYPE
+# if defined(STARBOARD)
+ typedef int8_t int8;
+ typedef int16_t int16;
+ typedef int32_t int32;
+ typedef int64_t int64;
+
+ typedef uint8_t uint8;
+ typedef uint16_t uint16;
+ typedef uint32_t uint32;
+ typedef uint64_t uint64;
+# elif GLM_HAS_EXTENDED_INTEGER_TYPE
typedef std::int8_t int8;
typedef std::int16_t int16;
typedef std::int32_t int32;
diff --git a/src/third_party/glm/glm/fwd.hpp b/src/third_party/glm/glm/fwd.hpp
index f90c4d0..2e04473 100644
--- a/src/third_party/glm/glm/fwd.hpp
+++ b/src/third_party/glm/glm/fwd.hpp
@@ -257,7 +257,9 @@
typedef detail::int64 int64;
-#if GLM_HAS_EXTENDED_INTEGER_TYPE
+#if defined(STARBOARD)
+ // Empty.
+#elif GLM_HAS_EXTENDED_INTEGER_TYPE
using std::int8_t;
using std::int16_t;
using std::int32_t;
@@ -866,7 +868,9 @@
/// @see gtc_type_precision
typedef detail::uint64 uint64;
-#if GLM_HAS_EXTENDED_INTEGER_TYPE
+#if defined(STARBOARD)
+ // Empty.
+#elif GLM_HAS_EXTENDED_INTEGER_TYPE
using std::uint8_t;
using std::uint16_t;
using std::uint32_t;
diff --git a/src/third_party/libxml/src/HTMLparser.c b/src/third_party/libxml/src/HTMLparser.c
index 3cb0388..c7a0658 100644
--- a/src/third_party/libxml/src/HTMLparser.c
+++ b/src/third_party/libxml/src/HTMLparser.c
@@ -3254,12 +3254,17 @@
ctxt->instate = state;
return;
}
+ len = 0;
+ buf[len] = 0;
q = CUR_CHAR(ql);
+ if (!IS_CHAR(q))
+ goto unfinished;
NEXTL(ql);
r = CUR_CHAR(rl);
+ if (!IS_CHAR(r))
+ goto unfinished;
NEXTL(rl);
cur = CUR_CHAR(l);
- len = 0;
while (IS_CHAR(cur) &&
((cur != '>') ||
(r != '-') || (q != '-'))) {
@@ -3290,18 +3295,19 @@
}
}
buf[len] = 0;
- if (!IS_CHAR(cur)) {
- htmlParseErr(ctxt, XML_ERR_COMMENT_NOT_FINISHED,
- "Comment not terminated \n<!--%.50s\n", buf, NULL);
- xmlFree(buf);
- } else {
+ if (IS_CHAR(cur)) {
NEXT;
if ((ctxt->sax != NULL) && (ctxt->sax->comment != NULL) &&
(!ctxt->disableSAX))
ctxt->sax->comment(ctxt->userData, buf);
xmlFree(buf);
+ ctxt->instate = state;
+ return;
}
- ctxt->instate = state;
+unfinished:
+ htmlParseErr(ctxt, XML_ERR_COMMENT_NOT_FINISHED,
+ "Comment not terminated \n<!--%.50s\n", buf, NULL);
+ xmlFree(buf);
}
/**
diff --git a/src/third_party/mozjs-45/INSTALL b/src/third_party/mozjs-45/INSTALL
new file mode 100644
index 0000000..c57135b
--- /dev/null
+++ b/src/third_party/mozjs-45/INSTALL
@@ -0,0 +1,13 @@
+Full build documentation for SpiderMonkey is hosted on MDN:
+ https://developer.mozilla.org/en-US/docs/SpiderMonkey/Build_Documentation
+
+Note that the libraries produced by the build system include symbols,
+causing the binaries to be extremely large. It is highly suggested that `strip`
+be run over the binaries before deploying them.
+
+Building with default options may be performed as follows:
+ cd js/src
+ mkdir obj
+ cd obj
+ ../configure
+ make # or mozmake on Windows
diff --git a/src/third_party/mozjs-45/LICENSE b/src/third_party/mozjs-45/LICENSE
new file mode 100644
index 0000000..14e2f77
--- /dev/null
+++ b/src/third_party/mozjs-45/LICENSE
@@ -0,0 +1,373 @@
+Mozilla Public License Version 2.0
+==================================
+
+1. Definitions
+--------------
+
+1.1. "Contributor"
+ means each individual or legal entity that creates, contributes to
+ the creation of, or owns Covered Software.
+
+1.2. "Contributor Version"
+ means the combination of the Contributions of others (if any) used
+ by a Contributor and that particular Contributor's Contribution.
+
+1.3. "Contribution"
+ means Covered Software of a particular Contributor.
+
+1.4. "Covered Software"
+ means Source Code Form to which the initial Contributor has attached
+ the notice in Exhibit A, the Executable Form of such Source Code
+ Form, and Modifications of such Source Code Form, in each case
+ including portions thereof.
+
+1.5. "Incompatible With Secondary Licenses"
+ means
+
+ (a) that the initial Contributor has attached the notice described
+ in Exhibit B to the Covered Software; or
+
+ (b) that the Covered Software was made available under the terms of
+ version 1.1 or earlier of the License, but not also under the
+ terms of a Secondary License.
+
+1.6. "Executable Form"
+ means any form of the work other than Source Code Form.
+
+1.7. "Larger Work"
+ means a work that combines Covered Software with other material, in
+ a separate file or files, that is not Covered Software.
+
+1.8. "License"
+ means this document.
+
+1.9. "Licensable"
+ means having the right to grant, to the maximum extent possible,
+ whether at the time of the initial grant or subsequently, any and
+ all of the rights conveyed by this License.
+
+1.10. "Modifications"
+ means any of the following:
+
+ (a) any file in Source Code Form that results from an addition to,
+ deletion from, or modification of the contents of Covered
+ Software; or
+
+ (b) any new file in Source Code Form that contains any Covered
+ Software.
+
+1.11. "Patent Claims" of a Contributor
+ means any patent claim(s), including without limitation, method,
+ process, and apparatus claims, in any patent Licensable by such
+ Contributor that would be infringed, but for the grant of the
+ License, by the making, using, selling, offering for sale, having
+ made, import, or transfer of either its Contributions or its
+ Contributor Version.
+
+1.12. "Secondary License"
+ means either the GNU General Public License, Version 2.0, the GNU
+ Lesser General Public License, Version 2.1, the GNU Affero General
+ Public License, Version 3.0, or any later versions of those
+ licenses.
+
+1.13. "Source Code Form"
+ means the form of the work preferred for making modifications.
+
+1.14. "You" (or "Your")
+ means an individual or a legal entity exercising rights under this
+ License. For legal entities, "You" includes any entity that
+ controls, is controlled by, or is under common control with You. For
+ purposes of this definition, "control" means (a) the power, direct
+ or indirect, to cause the direction or management of such entity,
+ whether by contract or otherwise, or (b) ownership of more than
+ fifty percent (50%) of the outstanding shares or beneficial
+ ownership of such entity.
+
+2. License Grants and Conditions
+--------------------------------
+
+2.1. Grants
+
+Each Contributor hereby grants You a world-wide, royalty-free,
+non-exclusive license:
+
+(a) under intellectual property rights (other than patent or trademark)
+ Licensable by such Contributor to use, reproduce, make available,
+ modify, display, perform, distribute, and otherwise exploit its
+ Contributions, either on an unmodified basis, with Modifications, or
+ as part of a Larger Work; and
+
+(b) under Patent Claims of such Contributor to make, use, sell, offer
+ for sale, have made, import, and otherwise transfer either its
+ Contributions or its Contributor Version.
+
+2.2. Effective Date
+
+The licenses granted in Section 2.1 with respect to any Contribution
+become effective for each Contribution on the date the Contributor first
+distributes such Contribution.
+
+2.3. Limitations on Grant Scope
+
+The licenses granted in this Section 2 are the only rights granted under
+this License. No additional rights or licenses will be implied from the
+distribution or licensing of Covered Software under this License.
+Notwithstanding Section 2.1(b) above, no patent license is granted by a
+Contributor:
+
+(a) for any code that a Contributor has removed from Covered Software;
+ or
+
+(b) for infringements caused by: (i) Your and any other third party's
+ modifications of Covered Software, or (ii) the combination of its
+ Contributions with other software (except as part of its Contributor
+ Version); or
+
+(c) under Patent Claims infringed by Covered Software in the absence of
+ its Contributions.
+
+This License does not grant any rights in the trademarks, service marks,
+or logos of any Contributor (except as may be necessary to comply with
+the notice requirements in Section 3.4).
+
+2.4. Subsequent Licenses
+
+No Contributor makes additional grants as a result of Your choice to
+distribute the Covered Software under a subsequent version of this
+License (see Section 10.2) or under the terms of a Secondary License (if
+permitted under the terms of Section 3.3).
+
+2.5. Representation
+
+Each Contributor represents that the Contributor believes its
+Contributions are its original creation(s) or it has sufficient rights
+to grant the rights to its Contributions conveyed by this License.
+
+2.6. Fair Use
+
+This License is not intended to limit any rights You have under
+applicable copyright doctrines of fair use, fair dealing, or other
+equivalents.
+
+2.7. Conditions
+
+Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted
+in Section 2.1.
+
+3. Responsibilities
+-------------------
+
+3.1. Distribution of Source Form
+
+All distribution of Covered Software in Source Code Form, including any
+Modifications that You create or to which You contribute, must be under
+the terms of this License. You must inform recipients that the Source
+Code Form of the Covered Software is governed by the terms of this
+License, and how they can obtain a copy of this License. You may not
+attempt to alter or restrict the recipients' rights in the Source Code
+Form.
+
+3.2. Distribution of Executable Form
+
+If You distribute Covered Software in Executable Form then:
+
+(a) such Covered Software must also be made available in Source Code
+ Form, as described in Section 3.1, and You must inform recipients of
+ the Executable Form how they can obtain a copy of such Source Code
+ Form by reasonable means in a timely manner, at a charge no more
+ than the cost of distribution to the recipient; and
+
+(b) You may distribute such Executable Form under the terms of this
+ License, or sublicense it under different terms, provided that the
+ license for the Executable Form does not attempt to limit or alter
+ the recipients' rights in the Source Code Form under this License.
+
+3.3. Distribution of a Larger Work
+
+You may create and distribute a Larger Work under terms of Your choice,
+provided that You also comply with the requirements of this License for
+the Covered Software. If the Larger Work is a combination of Covered
+Software with a work governed by one or more Secondary Licenses, and the
+Covered Software is not Incompatible With Secondary Licenses, this
+License permits You to additionally distribute such Covered Software
+under the terms of such Secondary License(s), so that the recipient of
+the Larger Work may, at their option, further distribute the Covered
+Software under the terms of either this License or such Secondary
+License(s).
+
+3.4. Notices
+
+You may not remove or alter the substance of any license notices
+(including copyright notices, patent notices, disclaimers of warranty,
+or limitations of liability) contained within the Source Code Form of
+the Covered Software, except that You may alter any license notices to
+the extent required to remedy known factual inaccuracies.
+
+3.5. Application of Additional Terms
+
+You may choose to offer, and to charge a fee for, warranty, support,
+indemnity or liability obligations to one or more recipients of Covered
+Software. However, You may do so only on Your own behalf, and not on
+behalf of any Contributor. You must make it absolutely clear that any
+such warranty, support, indemnity, or liability obligation is offered by
+You alone, and You hereby agree to indemnify every Contributor for any
+liability incurred by such Contributor as a result of warranty, support,
+indemnity or liability terms You offer. You may include additional
+disclaimers of warranty and limitations of liability specific to any
+jurisdiction.
+
+4. Inability to Comply Due to Statute or Regulation
+---------------------------------------------------
+
+If it is impossible for You to comply with any of the terms of this
+License with respect to some or all of the Covered Software due to
+statute, judicial order, or regulation then You must: (a) comply with
+the terms of this License to the maximum extent possible; and (b)
+describe the limitations and the code they affect. Such description must
+be placed in a text file included with all distributions of the Covered
+Software under this License. Except to the extent prohibited by statute
+or regulation, such description must be sufficiently detailed for a
+recipient of ordinary skill to be able to understand it.
+
+5. Termination
+--------------
+
+5.1. The rights granted under this License will terminate automatically
+if You fail to comply with any of its terms. However, if You become
+compliant, then the rights granted under this License from a particular
+Contributor are reinstated (a) provisionally, unless and until such
+Contributor explicitly and finally terminates Your grants, and (b) on an
+ongoing basis, if such Contributor fails to notify You of the
+non-compliance by some reasonable means prior to 60 days after You have
+come back into compliance. Moreover, Your grants from a particular
+Contributor are reinstated on an ongoing basis if such Contributor
+notifies You of the non-compliance by some reasonable means, this is the
+first time You have received notice of non-compliance with this License
+from such Contributor, and You become compliant prior to 30 days after
+Your receipt of the notice.
+
+5.2. If You initiate litigation against any entity by asserting a patent
+infringement claim (excluding declaratory judgment actions,
+counter-claims, and cross-claims) alleging that a Contributor Version
+directly or indirectly infringes any patent, then the rights granted to
+You by any and all Contributors for the Covered Software under Section
+2.1 of this License shall terminate.
+
+5.3. In the event of termination under Sections 5.1 or 5.2 above, all
+end user license agreements (excluding distributors and resellers) which
+have been validly granted by You or Your distributors under this License
+prior to termination shall survive termination.
+
+************************************************************************
+* *
+* 6. Disclaimer of Warranty *
+* ------------------------- *
+* *
+* Covered Software is provided under this License on an "as is" *
+* basis, without warranty of any kind, either expressed, implied, or *
+* statutory, including, without limitation, warranties that the *
+* Covered Software is free of defects, merchantable, fit for a *
+* particular purpose or non-infringing. The entire risk as to the *
+* quality and performance of the Covered Software is with You. *
+* Should any Covered Software prove defective in any respect, You *
+* (not any Contributor) assume the cost of any necessary servicing, *
+* repair, or correction. This disclaimer of warranty constitutes an *
+* essential part of this License. No use of any Covered Software is *
+* authorized under this License except under this disclaimer. *
+* *
+************************************************************************
+
+************************************************************************
+* *
+* 7. Limitation of Liability *
+* -------------------------- *
+* *
+* Under no circumstances and under no legal theory, whether tort *
+* (including negligence), contract, or otherwise, shall any *
+* Contributor, or anyone who distributes Covered Software as *
+* permitted above, be liable to You for any direct, indirect, *
+* special, incidental, or consequential damages of any character *
+* including, without limitation, damages for lost profits, loss of *
+* goodwill, work stoppage, computer failure or malfunction, or any *
+* and all other commercial damages or losses, even if such party *
+* shall have been informed of the possibility of such damages. This *
+* limitation of liability shall not apply to liability for death or *
+* personal injury resulting from such party's negligence to the *
+* extent applicable law prohibits such limitation. Some *
+* jurisdictions do not allow the exclusion or limitation of *
+* incidental or consequential damages, so this exclusion and *
+* limitation may not apply to You. *
+* *
+************************************************************************
+
+8. Litigation
+-------------
+
+Any litigation relating to this License may be brought only in the
+courts of a jurisdiction where the defendant maintains its principal
+place of business and such litigation shall be governed by laws of that
+jurisdiction, without reference to its conflict-of-law provisions.
+Nothing in this Section shall prevent a party's ability to bring
+cross-claims or counter-claims.
+
+9. Miscellaneous
+----------------
+
+This License represents the complete agreement concerning the subject
+matter hereof. If any provision of this License is held to be
+unenforceable, such provision shall be reformed only to the extent
+necessary to make it enforceable. Any law or regulation which provides
+that the language of a contract shall be construed against the drafter
+shall not be used to construe this License against a Contributor.
+
+10. Versions of the License
+---------------------------
+
+10.1. New Versions
+
+Mozilla Foundation is the license steward. Except as provided in Section
+10.3, no one other than the license steward has the right to modify or
+publish new versions of this License. Each version will be given a
+distinguishing version number.
+
+10.2. Effect of New Versions
+
+You may distribute the Covered Software under the terms of the version
+of the License under which You originally received the Covered Software,
+or under the terms of any subsequent version published by the license
+steward.
+
+10.3. Modified Versions
+
+If you create software not governed by this License, and you want to
+create a new license for such software, you may create and use a
+modified version of this License if you rename the license and remove
+any references to the name of the license steward (except to note that
+such modified license differs from this License).
+
+10.4. Distributing Source Code Form that is Incompatible With Secondary
+Licenses
+
+If You choose to distribute Source Code Form that is Incompatible With
+Secondary Licenses under the terms of this version of the License, the
+notice described in Exhibit B of this License must be attached.
+
+Exhibit A - Source Code Form License Notice
+-------------------------------------------
+
+ This Source Code Form is subject to the terms of the Mozilla Public
+ License, v. 2.0. If a copy of the MPL was not distributed with this
+ file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+If it is not possible or desirable to put the notice in a particular
+file, then You may include the notice in a location (such as a LICENSE
+file in a relevant directory) where a recipient would be likely to look
+for such a notice.
+
+You may add additional accurate notices of copyright ownership.
+
+Exhibit B - "Incompatible With Secondary Licenses" Notice
+---------------------------------------------------------
+
+ This Source Code Form is "Incompatible With Secondary Licenses", as
+ defined by the Mozilla Public License, v. 2.0.
diff --git a/src/third_party/mozjs-45/Makefile.in b/src/third_party/mozjs-45/Makefile.in
new file mode 100644
index 0000000..078ac34
--- /dev/null
+++ b/src/third_party/mozjs-45/Makefile.in
@@ -0,0 +1,336 @@
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+ifeq (,$(MAKE_VERSION))
+$(error GNU Make is required)
+endif
+make_min_ver := 3.81
+ifneq ($(make_min_ver),$(firstword $(sort $(make_min_ver) $(MAKE_VERSION))))
+$(error GNU Make $(make_min_ver) or higher is required)
+endif
+
+export TOPLEVEL_BUILD := 1
+
+default::
+
+ifdef MOZ_BUILD_APP
+include $(topsrcdir)/$(MOZ_BUILD_APP)/build.mk
+endif
+
+include $(topsrcdir)/config/config.mk
+
+GARBAGE_DIRS += _javagen _profile staticlib
+DIST_GARBAGE = config.cache config.log config.status* config-defs.h \
+ config/autoconf.mk \
+ mozilla-config.h \
+ netwerk/necko-config.h xpcom/xpcom-config.h xpcom/xpcom-private.h \
+ .mozconfig.mk
+
+ifdef JS_STANDALONE
+configure_dir = $(topsrcdir)/js/src
+else
+configure_dir = $(topsrcdir)
+endif
+
+ifndef TEST_MOZBUILD
+ifndef MOZ_PROFILE_USE
+# We need to explicitly put backend.RecursiveMakeBackend here
+# otherwise the rule in rules.mk doesn't run early enough.
+$(TIERS) binaries:: CLOBBER $(configure_dir)/configure config.status backend.RecursiveMakeBackend
+ifndef JS_STANDALONE
+ifdef COMPILE_ENVIRONMENT
+$(TIERS) binaries:: $(topsrcdir)/js/src/configure js/src/config.status
+endif
+endif
+endif
+endif
+
+ifdef JS_STANDALONE
+.PHONY: CLOBBER
+CLOBBER:
+else
+CLOBBER: $(topsrcdir)/CLOBBER
+ @echo 'STOP! The CLOBBER file has changed.'
+ @echo 'Please run the build through a sanctioned build wrapper, such as'
+ @echo '"mach build" or client.mk.'
+ @exit 1
+endif
+
+$(topsrcdir)/configure: $(topsrcdir)/configure.in
+$(topsrcdir)/js/src/configure: $(topsrcdir)/js/src/configure.in
+$(topsrcdir)/configure $(topsrcdir)/js/src/configure:
+ @echo 'STOP! $^ has changed, and your configure is out of date.'
+ @echo 'Please rerun autoconf and re-configure your build directory.'
+ @echo 'To ignore this message, touch "$@",'
+ @echo 'but your build might not succeed.'
+ @exit 1
+
+config.status: $(configure_dir)/configure
+js/src/config.status: $(topsrcdir)/js/src/configure
+config.status js/src/config.status:
+ @echo 'STOP! $^ has changed and needs to be run again.'
+ @echo 'Please rerun it.'
+ @echo 'To ignore this message, touch "$(CURDIR)/$@",'
+ @echo 'but your build might not succeed.'
+ @exit 1
+
+# Regenerate the build backend if it is out of date. We only have this rule in
+# this main make file because having it in rules.mk and applied to partial tree
+# builds resulted in a world of hurt. Gory details are in bug 877308.
+#
+# The mach build driver will ensure the backend is up to date for partial tree
+# builds. This cleanly avoids most of the pain.
+
+ifndef TEST_MOZBUILD
+backend.RecursiveMakeBackend:
+ @echo 'Build configuration changed. Regenerating backend.'
+ $(PYTHON) config.status
+
+Makefile: backend.RecursiveMakeBackend
+ @$(TOUCH) $@
+
+include backend.RecursiveMakeBackend.pp
+
+default:: backend.RecursiveMakeBackend
+endif
+
+install_manifests := \
+ $(addprefix dist/,bin branding idl include public private sdk xpi-stage) \
+ _tests \
+ $(NULL)
+install_manifest_depends = \
+ CLOBBER \
+ $(configure_dir)/configure \
+ config.status \
+ backend.RecursiveMakeBackend \
+ $(NULL)
+
+ifndef JS_STANDALONE
+ifdef COMPILE_ENVIRONMENT
+install_manifest_depends += \
+ $(topsrcdir)/js/src/configure \
+ js/src/config.status \
+ $(NULL)
+endif
+endif
+
+.PHONY: install-manifests
+install-manifests: $(addprefix install-,$(install_manifests))
+
+# process_install_manifest needs to be invoked with --no-remove when building
+# js as standalone because automated builds are building nspr separately and
+# that would remove the resulting files.
+# Eventually, a standalone js build would just be able to build nspr itself,
+# removing the need for the former.
+ifdef JS_STANDALONE
+NO_REMOVE=1
+endif
+
+.PHONY: $(addprefix install-,$(install_manifests))
+$(addprefix install-,$(filter dist/%,$(install_manifests))): install-dist/%: $(install_manifest_depends)
+ $(call py_action,process_install_manifest,$(if $(NO_REMOVE),--no-remove )$(DIST)/$* _build_manifests/install/dist_$*)
+
+# Dummy wrapper rule to allow the faster backend to piggy back
+install-dist_%: install-dist/% ;
+
+install-_tests: $(install_manifest_depends)
+ $(call py_action,process_install_manifest,$(if $(NO_REMOVE),--no-remove )_tests _build_manifests/install/_tests)
+
+# For compatibility
+.PHONY: install-tests
+install-tests: install-_tests
+
+include $(topsrcdir)/build/moz-automation.mk
+
+# dist and _tests should be purged during cleaning. However, we don't want them
+# purged during PGO builds because they contain some auto-generated files.
+ifneq ($(filter-out maybe_clobber_profiledbuild,$(MAKECMDGOALS)),)
+GARBAGE_DIRS += dist _tests
+endif
+
+# Windows PGO builds don't perform a clean before the 2nd pass. So, we want
+# to preserve content for the 2nd pass on Windows. Everywhere else, we always
+# process the install manifests as part of export.
+# For the binaries rule, not all the install manifests matter, so force only
+# the interesting ones to be done.
+ifdef MOZ_PROFILE_USE
+ifndef NO_PROFILE_GUIDED_OPTIMIZE
+ifneq ($(OS_ARCH)_$(GNU_CC), WINNT_)
+export:: install-manifests
+binaries::
+ @$(MAKE) install-manifests NO_REMOVE=1 install_manifests=dist/include
+endif
+endif
+else # !MOZ_PROFILE_USE (normal build)
+export:: install-manifests
+binaries::
+ @$(MAKE) install-manifests NO_REMOVE=1 install_manifests=dist/include
+endif
+
+# For historical reasons that are unknown, $(DIST)/sdk is always blown away
+# with no regard for PGO passes. This decision could probably be revisited.
+export:: install-dist/sdk
+
+ifndef JS_STANDALONE
+ifdef ENABLE_TESTS
+# Additional makefile targets to call automated test suites
+include $(topsrcdir)/testing/testsuite-targets.mk
+endif
+endif
+
+default all::
+ $(call BUILDSTATUS,TIERS $(TIERS) $(if $(MOZ_AUTOMATION),$(MOZ_AUTOMATION_TIERS)))
+
+include $(topsrcdir)/config/rules.mk
+
+distclean::
+ $(RM) $(DIST_GARBAGE)
+
+ifeq ($(OS_ARCH),WINNT)
+# we want to copy PDB files on Windows
+MAKE_SYM_STORE_ARGS := -c --vcs-info
+ifdef PDBSTR_PATH
+MAKE_SYM_STORE_ARGS += -i
+endif
+DUMP_SYMS_BIN ?= $(topsrcdir)/toolkit/crashreporter/tools/win32/dump_syms_vc$(_MSC_VER).exe
+# PDB files don't get moved to dist, so we need to scan the whole objdir
+MAKE_SYM_STORE_PATH := .
+endif
+ifeq ($(OS_ARCH),Darwin)
+# need to pass arch flags for universal builds
+ifdef UNIVERSAL_BINARY
+MAKE_SYM_STORE_ARGS := -c -a 'i386 x86_64' --vcs-info
+MAKE_SYM_STORE_PATH := $(DIST)/universal
+else
+MAKE_SYM_STORE_ARGS := -c -a $(OS_TEST) --vcs-info
+MAKE_SYM_STORE_PATH := $(DIST)/bin
+endif
+DUMP_SYMS_BIN ?= $(DIST)/host/bin/dump_syms
+endif
+ifeq (,$(filter-out Linux SunOS,$(OS_ARCH)))
+MAKE_SYM_STORE_ARGS := -c --vcs-info
+DUMP_SYMS_BIN ?= $(DIST)/host/bin/dump_syms
+MAKE_SYM_STORE_PATH := $(DIST)/bin
+endif
+MAKE_SYM_STORE_ARGS += --install-manifest=$(DEPTH)/_build_manifests/install/dist_include,$(DIST)/include
+
+SYM_STORE_SOURCE_DIRS := $(topsrcdir)
+
+ifndef JS_STANDALONE
+include $(topsrcdir)/toolkit/mozapps/installer/package-name.mk
+
+ifdef MOZ_SYMBOLS_EXTRA_BUILDID
+EXTRA_BUILDID := -$(MOZ_SYMBOLS_EXTRA_BUILDID)
+endif
+
+SYMBOL_INDEX_NAME = \
+ $(MOZ_APP_NAME)-$(MOZ_APP_VERSION)-$(OS_TARGET)-$(BUILDID)-$(CPU_ARCH)$(EXTRA_BUILDID)-symbols.txt
+
+buildsymbols:
+ifdef MOZ_CRASHREPORTER
+ echo building symbol store
+ $(RM) -r $(DIST)/crashreporter-symbols
+ $(RM) '$(DIST)/$(SYMBOL_ARCHIVE_BASENAME).zip'
+ $(RM) '$(DIST)/$(SYMBOL_FULL_ARCHIVE_BASENAME).zip'
+ $(NSINSTALL) -D $(DIST)/crashreporter-symbols
+ OBJCOPY='$(OBJCOPY)' \
+ $(PYTHON) $(topsrcdir)/toolkit/crashreporter/tools/symbolstore.py \
+ $(MAKE_SYM_STORE_ARGS) \
+ $(foreach dir,$(SYM_STORE_SOURCE_DIRS),-s $(dir)) \
+ $(DUMP_SYMS_BIN) \
+ $(DIST)/crashreporter-symbols \
+ $(MAKE_SYM_STORE_PATH) | grep -iv test > \
+ $(DIST)/crashreporter-symbols/$(SYMBOL_INDEX_NAME)
+ echo packing symbols
+ $(NSINSTALL) -D $(DIST)/$(PKG_PATH)
+ cd $(DIST)/crashreporter-symbols && \
+ zip -r9D '../$(PKG_PATH)$(SYMBOL_FULL_ARCHIVE_BASENAME).zip' . -x '*test*' -x '*Test*'
+ cd $(DIST)/crashreporter-symbols && \
+ grep 'sym' $(SYMBOL_INDEX_NAME) > $(SYMBOL_INDEX_NAME).tmp && \
+ mv $(SYMBOL_INDEX_NAME).tmp $(SYMBOL_INDEX_NAME)
+ cd $(DIST)/crashreporter-symbols && \
+ zip -r9D '../$(PKG_PATH)$(SYMBOL_ARCHIVE_BASENAME).zip' . -i '*.sym' -i '*.txt' -x '*test*' -x '*Test*'
+endif # MOZ_CRASHREPORTER
+
+uploadsymbols:
+ifdef MOZ_CRASHREPORTER
+ifdef SOCORRO_SYMBOL_UPLOAD_TOKEN_FILE
+ $(PYTHON) -u $(topsrcdir)/toolkit/crashreporter/tools/upload_symbols.py '$(DIST)/$(PKG_PATH)$(SYMBOL_FULL_ARCHIVE_BASENAME).zip'
+else
+ $(SHELL) $(topsrcdir)/toolkit/crashreporter/tools/upload_symbols.sh $(SYMBOL_INDEX_NAME) '$(DIST)/$(PKG_PATH)$(SYMBOL_FULL_ARCHIVE_BASENAME).zip'
+endif
+endif
+
+# MOZ_SOURCE_STAMP is defined in package-name.mk with a deferred assignment.
+# exporting it makes make run its $(shell) command for each invoked submake,
+# so transform it to an immediate assignment.
+MOZ_SOURCE_STAMP := $(MOZ_SOURCE_STAMP)
+export MOZ_SOURCE_STAMP
+endif
+
+.PHONY: update-packaging
+update-packaging:
+ $(MAKE) -C tools/update-packaging
+
+.PHONY: pretty-package
+pretty-package:
+ unset MOZ_SIGN_CMD && $(MAKE) package MOZ_PKG_PRETTYNAMES=1
+
+.PHONY: pretty-package-tests
+pretty-package-tests:
+ unset MOZ_SIGN_CMD && $(MAKE) package-tests MOZ_PKG_PRETTYNAMES=1
+
+.PHONY: pretty-l10n-check
+pretty-l10n-check:
+ unset MOZ_SIGN_CMD && $(MAKE) l10n-check MOZ_PKG_PRETTYNAMES=1
+
+.PHONY: pretty-update-packaging
+pretty-update-packaging:
+ unset MOZ_SIGN_CMD && $(MAKE) -C tools/update-packaging MOZ_PKG_PRETTYNAMES=1
+
+.PHONY: pretty-installer
+pretty-installer:
+ unset MOZ_SIGN_CMD && $(MAKE) installer MOZ_PKG_PRETTYNAMES=1
+
+#XXX: this is a hack, since we don't want to clobber for MSVC
+# PGO support, but we can't do this test in client.mk
+ifneq ($(OS_ARCH)_$(GNU_CC), WINNT_)
+# No point in clobbering if PGO has been explicitly disabled.
+ifndef NO_PROFILE_GUIDED_OPTIMIZE
+maybe_clobber_profiledbuild: clean
+else
+maybe_clobber_profiledbuild:
+endif
+else
+maybe_clobber_profiledbuild:
+ $(RM) $(DIST)/bin/*.pgc
+ find $(DIST)/$(MOZ_APP_NAME) -name '*.pgc' -exec mv {} $(DIST)/bin \;
+endif
+
+.PHONY: maybe_clobber_profiledbuild
+
+# Look for R_386_PC32 relocations in shared libs, these
+# break x86_64 builds and SELinux users.
+ifeq ($(OS_TARGET)_$(TARGET_XPCOM_ABI),Linux_x86-gcc3)
+check::
+ @relcount=`find $(DIST)/bin -name '*.so' | xargs objdump -R | grep R_386_PC32 | wc -l` && if test $$relcount -gt 0; then echo 'FAILED: R_386_PC32 relocations detected in a shared library. Did you use a system header without adding it to config/system-headers?'; exit 1; else echo 'PASSED'; fi
+endif
+
+ifdef JS_STANDALONE
+# Delegate js-specific rules to js
+check-%:
+ $(MAKE) -C js/src $@
+
+source-package install:
+ $(MAKE) -C js/src $@
+
+# Every export rule depends on config/export, but the rule for config/export
+# doesn't exist when building js non-standalone.
+.PHONY: config/export
+config/export:
+
+endif
+
+# There used to be build interdependencies here. They are now in config/recurse.mk
diff --git a/src/third_party/mozjs-45/README b/src/third_party/mozjs-45/README
new file mode 100644
index 0000000..5a7fff7
--- /dev/null
+++ b/src/third_party/mozjs-45/README
@@ -0,0 +1,8 @@
+This directory contains SpiderMonkey 45.
+
+This release is based on a revision of Mozilla 45:
+ http://hg.mozilla.org/releases/
+The changes in the patches/ directory were applied.
+
+MDN hosts the latest SpiderMonkey 45 release notes:
+ https://developer.mozilla.org/en-US/docs/SpiderMonkey/45
diff --git a/src/third_party/mozjs-45/build/.lldbinit.in b/src/third_party/mozjs-45/build/.lldbinit.in
new file mode 100644
index 0000000..425ca0f
--- /dev/null
+++ b/src/third_party/mozjs-45/build/.lldbinit.in
@@ -0,0 +1,2 @@
+#filter substitution
+script topsrcdir = "@topsrcdir@"; lldb.debugger.HandleCommand("command source -s true '%s'" % os.path.join(topsrcdir, ".lldbinit"))
diff --git a/src/third_party/mozjs-45/build/Makefile.in b/src/third_party/mozjs-45/build/Makefile.in
new file mode 100644
index 0000000..2d82093
--- /dev/null
+++ b/src/third_party/mozjs-45/build/Makefile.in
@@ -0,0 +1,100 @@
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+USE_RCS_MK := 1
+include $(topsrcdir)/config/makefiles/makeutils.mk
+
+ifdef MOZ_APP_BASENAME
+APP_INI_DEPS = $(topsrcdir)/config/milestone.txt
+
+MOZ_APP_BUILDID := $(shell cat $(DEPTH)/config/buildid)
+APP_INI_DEPS += $(DEPTH)/config/buildid
+
+DEFINES += -DMOZ_APP_BUILDID=$(MOZ_APP_BUILDID)
+
+APP_INI_DEPS += $(DEPTH)/config/autoconf.mk
+
+MOZ_SOURCE_STAMP := $(firstword $(shell cd $(topsrcdir)/$(MOZ_BUILD_APP)/.. && hg parent --template='{node}\n' 2>/dev/null))
+ifdef MOZ_SOURCE_STAMP
+DEFINES += -DMOZ_SOURCE_STAMP='$(MOZ_SOURCE_STAMP)'
+endif
+
+ifdef MOZ_INCLUDE_SOURCE_INFO
+source_repo ?= $(call getSourceRepo,$(topsrcdir)/$(MOZ_BUILD_APP)/..)
+ifneq (,$(source_repo))
+ DEFINES += -DMOZ_SOURCE_REPO='$(source_repo)'
+endif
+endif
+
+endif
+
+# NOTE: Keep .gdbinit in the topsrcdir for people who run gdb from the topsrcdir.
+# needs to be absolute to be distinct from $(topsrcdir)/.gdbinit
+GDBINIT_OBJDIR_FILES = $(topsrcdir)/.gdbinit
+GDBINIT_OBJDIR_DEST = $(abspath $(DEPTH))
+INSTALL_TARGETS += GDBINIT_OBJDIR
+
+# Put a .lldbinit in the bin directory and the objdir, to be picked up
+# automatically by LLDB when we debug executables using either of those two
+# directories as the current working directory. The .lldbinit file will
+# load $(topsrcdir)/.lldbinit, which is where the actual debugging commands are.
+LLDBINIT_OBJDIR := .lldbinit.in
+LLDBINIT_OBJDIR_PATH = $(DEPTH)
+LLDBINIT_OBJDIR_FLAGS += -Dtopsrcdir=$(abspath $(topsrcdir))
+PP_TARGETS += LLDBINIT_OBJDIR
+
+LLDBINIT_FINAL_TARGET_FILES := $(DEPTH)/.lldbinit
+LLDBINIT_FINAL_TARGET_DEST = $(FINAL_TARGET)
+INSTALL_TARGETS += LLDBINIT_FINAL_TARGET
+
+# Put the .ycm_extra_conf.py file at the root of the objdir. It is used by
+# the vim plugin YouCompleteMe.
+YCM_FILES := $(topsrcdir)/.ycm_extra_conf.py
+YCM_DEST := $(abspath $(DEPTH))
+YCM_TARGET := export
+INSTALL_TARGETS += YCM
+
+ifdef MOZTTDIR
+# Install the Firefox OS fonts.
+include $(MOZTTDIR)/fonts.mk
+MOZTT_DEST = $(FINAL_TARGET)/fonts
+ifdef MOZ_B2GDROID
+MOZTT_DEST = $(FINAL_TARGET)/res/fonts
+endif
+MOZTT_FILES = $(patsubst external/moztt/%,$(MOZTTDIR)/%,$(filter external/moztt/%,$(subst :, ,$(PRODUCT_COPY_FILES))))
+INSTALL_TARGETS += MOZTT
+endif
+
+ifdef MOZ_VALGRIND
+_VALGRIND_DIR = $(DEPTH)/_valgrind
+GARBAGE_DIRS += $(_VALGRIND_DIR)
+
+_VALGRIND_FILES = \
+ $(topsrcdir)/build/valgrind/cross-architecture.sup \
+ $(topsrcdir)/build/valgrind/i386-redhat-linux-gnu.sup \
+ $(topsrcdir)/build/valgrind/x86_64-redhat-linux-gnu.sup \
+ $(NULL)
+_VALGRIND_DEST = $(_VALGRIND_DIR)
+INSTALL_TARGETS += _VALGRIND
+endif
+
+include $(topsrcdir)/config/rules.mk
+
+TARGET_DEPTH = ..
+include $(srcdir)/automation-build.mk
+
+ifdef MOZ_APP_BASENAME
+$(FINAL_TARGET)/application.ini: $(APP_INI_DEPS)
+
+ifdef MOZ_APP_STATIC_INI
+application.ini.h: appini_header.py $(FINAL_TARGET)/application.ini
+ $(PYTHON) $^ > $@
+export:: application.ini.h
+GARBAGE += application.ini.h
+endif
+endif
+
+libs:: automation.py
+
diff --git a/src/third_party/mozjs-45/build/__init__.py b/src/third_party/mozjs-45/build/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/src/third_party/mozjs-45/build/__init__.py
diff --git a/src/third_party/mozjs-45/build/annotationProcessors/AnnotationInfo.java b/src/third_party/mozjs-45/build/annotationProcessors/AnnotationInfo.java
new file mode 100644
index 0000000..2477132
--- /dev/null
+++ b/src/third_party/mozjs-45/build/annotationProcessors/AnnotationInfo.java
@@ -0,0 +1,30 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+package org.mozilla.gecko.annotationProcessors;
+
+/**
+ * Object holding annotation data. Used by GeneratableElementIterator.
+ */
+public class AnnotationInfo {
+ public final String wrapperName;
+ public final boolean isMultithreaded;
+ public final boolean noThrow;
+ public final boolean narrowChars;
+ public final boolean catchException;
+
+ public AnnotationInfo(String aWrapperName, boolean aIsMultithreaded,
+ boolean aNoThrow, boolean aNarrowChars, boolean aCatchException) {
+ wrapperName = aWrapperName;
+ isMultithreaded = aIsMultithreaded;
+ noThrow = aNoThrow;
+ narrowChars = aNarrowChars;
+ catchException = aCatchException;
+
+ if (noThrow && catchException) {
+ // It doesn't make sense to have these together
+ throw new IllegalArgumentException("noThrow and catchException are not allowed together");
+ }
+ }
+}
diff --git a/src/third_party/mozjs-45/build/annotationProcessors/AnnotationProcessor.java b/src/third_party/mozjs-45/build/annotationProcessors/AnnotationProcessor.java
new file mode 100644
index 0000000..f852655
--- /dev/null
+++ b/src/third_party/mozjs-45/build/annotationProcessors/AnnotationProcessor.java
@@ -0,0 +1,173 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+package org.mozilla.gecko.annotationProcessors;
+
+import org.mozilla.gecko.annotationProcessors.classloader.AnnotatableEntity;
+import org.mozilla.gecko.annotationProcessors.classloader.ClassWithOptions;
+import org.mozilla.gecko.annotationProcessors.classloader.IterableJarLoadingURLClassLoader;
+import org.mozilla.gecko.annotationProcessors.utils.GeneratableElementIterator;
+
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.util.Arrays;
+import java.util.Iterator;
+
+public class AnnotationProcessor {
+ public static final String SOURCE_FILE = "GeneratedJNIWrappers.cpp";
+ public static final String HEADER_FILE = "GeneratedJNIWrappers.h";
+ public static final String NATIVES_FILE = "GeneratedJNINatives.h";
+
+ public static final String GENERATED_COMMENT =
+ "// GENERATED CODE\n" +
+ "// Generated by the Java program at /build/annotationProcessors at compile time\n" +
+ "// from annotations on Java methods. To update, change the annotations on the\n" +
+ "// corresponding Java methods and rerun the build. Manually updating this file\n" +
+ "// will cause your build to fail.\n" +
+ "\n";
+
+ private static final StringBuilder headerFile = new StringBuilder(GENERATED_COMMENT);
+ private static final StringBuilder implementationFile = new StringBuilder(GENERATED_COMMENT);
+ private static final StringBuilder nativesFile = new StringBuilder(GENERATED_COMMENT);
+
+ public static void main(String[] args) {
+ // We expect a list of jars on the commandline. If missing, whinge about it.
+ if (args.length <= 1) {
+ System.err.println("Usage: java AnnotationProcessor jarfiles ...");
+ System.exit(1);
+ }
+
+ System.out.println("Processing annotations...");
+
+ // We want to produce the same output as last time as often as possible. Ordering of
+ // generated statements, therefore, needs to be consistent.
+ Arrays.sort(args);
+
+ // Start the clock!
+ long s = System.currentTimeMillis();
+
+ // Get an iterator over the classes in the jar files given...
+ Iterator<ClassWithOptions> jarClassIterator = IterableJarLoadingURLClassLoader.getIteratorOverJars(args);
+
+ headerFile.append(
+ "#ifndef " + getHeaderGuardName(HEADER_FILE) + "\n" +
+ "#define " + getHeaderGuardName(HEADER_FILE) + "\n" +
+ "\n" +
+ "#include \"mozilla/jni/Refs.h\"\n" +
+ "\n" +
+ "namespace mozilla {\n" +
+ "namespace widget {\n" +
+ "\n");
+
+ implementationFile.append(
+ "#include \"GeneratedJNIWrappers.h\"\n" +
+ "#include \"mozilla/jni/Accessors.h\"\n" +
+ "\n" +
+ "namespace mozilla {\n" +
+ "namespace widget {\n" +
+ "\n");
+
+ nativesFile.append(
+ "#ifndef " + getHeaderGuardName(NATIVES_FILE) + "\n" +
+ "#define " + getHeaderGuardName(NATIVES_FILE) + "\n" +
+ "\n" +
+ "#include \"GeneratedJNIWrappers.h\"\n" +
+ "#include \"mozilla/jni/Natives.h\"\n" +
+ "\n" +
+ "namespace mozilla {\n" +
+ "namespace widget {\n" +
+ "\n");
+
+ while (jarClassIterator.hasNext()) {
+ generateClass(jarClassIterator.next());
+ }
+
+ implementationFile.append(
+ "} /* widget */\n" +
+ "} /* mozilla */\n");
+
+ headerFile.append(
+ "} /* widget */\n" +
+ "} /* mozilla */\n" +
+ "#endif // " + getHeaderGuardName(HEADER_FILE) + "\n");
+
+ nativesFile.append(
+ "} /* widget */\n" +
+ "} /* mozilla */\n" +
+ "#endif // " + getHeaderGuardName(NATIVES_FILE) + "\n");
+
+ writeOutputFile(SOURCE_FILE, implementationFile);
+ writeOutputFile(HEADER_FILE, headerFile);
+ writeOutputFile(NATIVES_FILE, nativesFile);
+
+ long e = System.currentTimeMillis();
+ System.out.println("Annotation processing complete in " + (e - s) + "ms");
+ }
+
+ private static void generateClass(final ClassWithOptions annotatedClass) {
+ // Get an iterator over the appropriately generated methods of this class
+ final GeneratableElementIterator methodIterator
+ = new GeneratableElementIterator(annotatedClass);
+ final ClassWithOptions[] innerClasses = methodIterator.getInnerClasses();
+
+ if (!methodIterator.hasNext() && innerClasses.length == 0) {
+ return;
+ }
+
+ final CodeGenerator generatorInstance = new CodeGenerator(annotatedClass);
+ generatorInstance.generateClasses(innerClasses);
+
+ // Iterate all annotated members in this class..
+ while (methodIterator.hasNext()) {
+ AnnotatableEntity aElementTuple = methodIterator.next();
+ switch (aElementTuple.mEntityType) {
+ case METHOD:
+ generatorInstance.generateMethod(aElementTuple);
+ break;
+ case NATIVE:
+ generatorInstance.generateNative(aElementTuple);
+ break;
+ case FIELD:
+ generatorInstance.generateField(aElementTuple);
+ break;
+ case CONSTRUCTOR:
+ generatorInstance.generateConstructor(aElementTuple);
+ break;
+ }
+ }
+
+ headerFile.append(generatorInstance.getHeaderFileContents());
+ implementationFile.append(generatorInstance.getWrapperFileContents());
+ nativesFile.append(generatorInstance.getNativesFileContents());
+
+ for (ClassWithOptions innerClass : innerClasses) {
+ generateClass(innerClass);
+ }
+ }
+
+ private static String getHeaderGuardName(final String name) {
+ return name.replaceAll("\\W", "_");
+ }
+
+ private static void writeOutputFile(final String name,
+ final StringBuilder content) {
+ FileOutputStream outStream = null;
+ try {
+ outStream = new FileOutputStream(name);
+ outStream.write(content.toString().getBytes());
+ } catch (IOException e) {
+ System.err.println("Unable to write " + name + ". Perhaps a permissions issue?");
+ e.printStackTrace(System.err);
+ } finally {
+ if (outStream != null) {
+ try {
+ outStream.close();
+ } catch (IOException e) {
+ System.err.println("Unable to close outStream due to "+e);
+ e.printStackTrace(System.err);
+ }
+ }
+ }
+ }
+}
diff --git a/src/third_party/mozjs-45/build/annotationProcessors/CodeGenerator.java b/src/third_party/mozjs-45/build/annotationProcessors/CodeGenerator.java
new file mode 100644
index 0000000..f96026e
--- /dev/null
+++ b/src/third_party/mozjs-45/build/annotationProcessors/CodeGenerator.java
@@ -0,0 +1,578 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+package org.mozilla.gecko.annotationProcessors;
+
+import org.mozilla.gecko.annotationProcessors.classloader.AnnotatableEntity;
+import org.mozilla.gecko.annotationProcessors.classloader.ClassWithOptions;
+import org.mozilla.gecko.annotationProcessors.utils.Utils;
+
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Field;
+import java.lang.reflect.Member;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.util.HashSet;
+
+public class CodeGenerator {
+ private static final Class<?>[] EMPTY_CLASS_ARRAY = new Class<?>[0];
+
+ // Buffers holding the strings to ultimately be written to the output files.
+ private final StringBuilder cpp = new StringBuilder();
+ private final StringBuilder header = new StringBuilder();
+ private final StringBuilder natives = new StringBuilder();
+ private final StringBuilder nativesInits = new StringBuilder();
+
+ private final Class<?> cls;
+ private final String clsName;
+
+ private final HashSet<String> takenMethodNames = new HashSet<String>();
+
+ public CodeGenerator(ClassWithOptions annotatedClass) {
+ this.cls = annotatedClass.wrappedClass;
+ this.clsName = annotatedClass.generatedName;
+
+ final String unqualifiedName = Utils.getUnqualifiedName(clsName);
+ header.append(
+ "class " + clsName + " : public mozilla::jni::Class<" + unqualifiedName + ">\n" +
+ "{\n" +
+ "public:\n" +
+ " typedef mozilla::jni::Ref<" + unqualifiedName + "> Ref;\n" +
+ " typedef mozilla::jni::LocalRef<" + unqualifiedName + "> LocalRef;\n" +
+ " typedef mozilla::jni::GlobalRef<" + unqualifiedName + "> GlobalRef;\n" +
+ " typedef const mozilla::jni::Param<" + unqualifiedName + ">& Param;\n" +
+ "\n" +
+ " static constexpr char name[] =\n" +
+ " \"" + cls.getName().replace('.', '/') + "\";\n" +
+ "\n" +
+ "protected:\n" +
+ " " + unqualifiedName + "(jobject instance) : Class(instance) {}\n" +
+ "\n");
+
+ cpp.append(
+ "constexpr char " + clsName + "::name[];\n" +
+ "\n");
+
+ natives.append(
+ "template<class Impl>\n" +
+ "class " + clsName + "::Natives : " +
+ "public mozilla::jni::NativeImpl<" + unqualifiedName + ", Impl>\n" +
+ "{\n");
+ }
+
+ private String getTraitsName(String uniqueName, boolean includeScope) {
+ return (includeScope ? clsName + "::" : "") + uniqueName + "_t";
+ }
+
+ /**
+ * Return the C++ type name for this class or any class within the chain
+ * of declaring classes, if the target class matches the given type.
+ *
+ * Return null if the given type does not match any class searched.
+ */
+ private String getMatchingClassType(final Class<?> type) {
+ Class<?> cls = this.cls;
+ String clsName = this.clsName;
+
+ while (cls != null) {
+ if (type.equals(cls)) {
+ return clsName;
+ }
+ cls = cls.getDeclaringClass();
+ clsName = clsName.substring(0, Math.max(0, clsName.lastIndexOf("::")));
+ }
+ return null;
+ }
+
+ private String getNativeParameterType(Class<?> type, AnnotationInfo info) {
+ final String clsName = getMatchingClassType(type);
+ if (clsName != null) {
+ return Utils.getUnqualifiedName(clsName) + "::Param";
+ }
+ return Utils.getNativeParameterType(type, info);
+ }
+
+ private String getNativeReturnType(Class<?> type, AnnotationInfo info) {
+ final String clsName = getMatchingClassType(type);
+ if (clsName != null) {
+ return Utils.getUnqualifiedName(clsName) + "::LocalRef";
+ }
+ return Utils.getNativeReturnType(type, info);
+ }
+
+ private void generateMember(AnnotationInfo info, Member member,
+ String uniqueName, Class<?> type, Class<?>[] argTypes) {
+ final StringBuilder args = new StringBuilder();
+ for (Class<?> argType : argTypes) {
+ args.append("\n " + getNativeParameterType(argType, info) + ",");
+ }
+ if (args.length() > 0) {
+ args.setLength(args.length() - 1);
+ }
+
+ header.append(
+ "public:\n" +
+ " struct " + getTraitsName(uniqueName, /* includeScope */ false) + " {\n" +
+ " typedef " + Utils.getUnqualifiedName(clsName) + " Owner;\n" +
+ " typedef " + getNativeReturnType(type, info) + " ReturnType;\n" +
+ " typedef " + getNativeParameterType(type, info) + " SetterType;\n" +
+ " typedef mozilla::jni::Args<" + args + "> Args;\n" +
+ " static constexpr char name[] = \"" +
+ Utils.getMemberName(member) + "\";\n" +
+ " static constexpr char signature[] =\n" +
+ " \"" + Utils.getSignature(member) + "\";\n" +
+ " static const bool isStatic = " + Utils.isStatic(member) + ";\n" +
+ " static const bool isMultithreaded = " + info.isMultithreaded + ";\n" +
+ " static const mozilla::jni::ExceptionMode exceptionMode =\n" +
+ " " + (
+ info.catchException ? "mozilla::jni::ExceptionMode::NSRESULT" :
+ info.noThrow ? "mozilla::jni::ExceptionMode::IGNORE" :
+ "mozilla::jni::ExceptionMode::ABORT") + ";\n" +
+ " };\n" +
+ "\n");
+
+ cpp.append(
+ "constexpr char " + getTraitsName(uniqueName, /* includeScope */ true) +
+ "::name[];\n" +
+ "constexpr char " + getTraitsName(uniqueName, /* includeScope */ true) +
+ "::signature[];\n" +
+ "\n");
+ }
+
+ private String getUniqueMethodName(String basename) {
+ String newName = basename;
+ int index = 1;
+
+ while (takenMethodNames.contains(newName)) {
+ newName = basename + (++index);
+ }
+
+ takenMethodNames.add(newName);
+ return newName;
+ }
+
+ /**
+ * Generate a method prototype that includes return and argument types,
+ * without specifiers (static, const, etc.).
+ */
+ private String generatePrototype(String name, Class<?>[] argTypes,
+ Class<?> returnType, AnnotationInfo info,
+ boolean includeScope, boolean includeArgName,
+ boolean isConst) {
+
+ final StringBuilder proto = new StringBuilder();
+ int argIndex = 0;
+
+ proto.append("auto ");
+
+ if (includeScope) {
+ proto.append(clsName).append("::");
+ }
+
+ proto.append(name).append('(');
+
+ for (Class<?> argType : argTypes) {
+ proto.append(getNativeParameterType(argType, info));
+ if (includeArgName) {
+ proto.append(" a").append(argIndex++);
+ }
+ proto.append(", ");
+ }
+
+ if (info.catchException && !returnType.equals(void.class)) {
+ proto.append(getNativeReturnType(returnType, info)).append('*');
+ if (includeArgName) {
+ proto.append(" a").append(argIndex++);
+ }
+ proto.append(", ");
+ }
+
+ if (proto.substring(proto.length() - 2).equals(", ")) {
+ proto.setLength(proto.length() - 2);
+ }
+
+ proto.append(')');
+
+ if (isConst) {
+ proto.append(" const");
+ }
+
+ if (info.catchException) {
+ proto.append(" -> nsresult");
+ } else {
+ proto.append(" -> ").append(getNativeReturnType(returnType, info));
+ }
+ return proto.toString();
+ }
+
+ /**
+ * Generate a method declaration that includes the prototype with specifiers,
+ * but without the method body.
+ */
+ private String generateDeclaration(String name, Class<?>[] argTypes,
+ Class<?> returnType, AnnotationInfo info,
+ boolean isStatic) {
+
+ return (isStatic ? "static " : "") +
+ generatePrototype(name, argTypes, returnType, info,
+ /* includeScope */ false, /* includeArgName */ false,
+ /* isConst */ !isStatic) + ';';
+ }
+
+ /**
+ * Generate a method definition that includes the prototype with specifiers,
+ * and with the method body.
+ */
+ private String generateDefinition(String accessorName, String name, Class<?>[] argTypes,
+ Class<?> returnType, AnnotationInfo info, boolean isStatic) {
+
+ final StringBuilder def = new StringBuilder(
+ generatePrototype(name, argTypes, returnType, info,
+ /* includeScope */ true, /* includeArgName */ true,
+ /* isConst */ !isStatic));
+ def.append("\n{\n");
+
+
+ // Generate code to handle the return value, if needed.
+ // We initialize rv to NS_OK instead of NS_ERROR_* because loading NS_OK (0) uses
+ // fewer instructions. We are guaranteed to set rv to the correct value later.
+
+ if (info.catchException && returnType.equals(void.class)) {
+ def.append(
+ " nsresult rv = NS_OK;\n" +
+ " ");
+
+ } else if (info.catchException) {
+ // Non-void return type
+ final String resultArg = "a" + argTypes.length;
+ def.append(
+ " MOZ_ASSERT(" + resultArg + ");\n" +
+ " nsresult rv = NS_OK;\n" +
+ " *" + resultArg + " = ");
+
+ } else {
+ def.append(
+ " return ");
+ }
+
+
+ // Generate a call, e.g., Method<Traits>::Call(a0, a1, a2);
+
+ def.append(accessorName).append("(")
+ .append(isStatic ? "nullptr" : "this");
+
+ if (info.catchException) {
+ def.append(", &rv");
+ } else {
+ def.append(", nullptr");
+ }
+
+ // Generate the call argument list.
+ for (int argIndex = 0; argIndex < argTypes.length; argIndex++) {
+ def.append(", a").append(argIndex);
+ }
+
+ def.append(");\n");
+
+
+ if (info.catchException) {
+ def.append(" return rv;\n");
+ }
+
+ return def.append("}").toString();
+ }
+
+ /**
+ * Append the appropriate generated code to the buffers for the method provided.
+ *
+ * @param annotatedMethod The Java method, plus annotation data.
+ */
+ public void generateMethod(AnnotatableEntity annotatedMethod) {
+ // Unpack the tuple and extract some useful fields from the Method..
+ final Method method = annotatedMethod.getMethod();
+ final AnnotationInfo info = annotatedMethod.mAnnotationInfo;
+ final String uniqueName = getUniqueMethodName(info.wrapperName);
+ final Class<?>[] argTypes = method.getParameterTypes();
+ final Class<?> returnType = method.getReturnType();
+
+ if (method.isSynthetic()) {
+ return;
+ }
+
+ generateMember(info, method, uniqueName, returnType, argTypes);
+
+ final boolean isStatic = Utils.isStatic(method);
+
+ header.append(
+ " " + generateDeclaration(info.wrapperName, argTypes,
+ returnType, info, isStatic) + "\n" +
+ "\n");
+
+ cpp.append(
+ generateDefinition(
+ "mozilla::jni::Method<" +
+ getTraitsName(uniqueName, /* includeScope */ false) + ">::Call",
+ info.wrapperName, argTypes, returnType, info, isStatic) + "\n" +
+ "\n");
+ }
+
+ /**
+ * Append the appropriate generated code to the buffers for the native method provided.
+ *
+ * @param annotatedMethod The Java native method, plus annotation data.
+ */
+ public void generateNative(AnnotatableEntity annotatedMethod) {
+ // Unpack the tuple and extract some useful fields from the Method..
+ final Method method = annotatedMethod.getMethod();
+ final AnnotationInfo info = annotatedMethod.mAnnotationInfo;
+ final String uniqueName = getUniqueMethodName(info.wrapperName);
+ final Class<?>[] argTypes = method.getParameterTypes();
+ final Class<?> returnType = method.getReturnType();
+
+ generateMember(info, method, uniqueName, returnType, argTypes);
+
+ final String traits = getTraitsName(uniqueName, /* includeScope */ true);
+
+ if (nativesInits.length() > 0) {
+ nativesInits.append(',');
+ }
+
+ nativesInits.append(
+ "\n" +
+ "\n" +
+ " mozilla::jni::MakeNativeMethod<" + traits + ">(\n" +
+ " mozilla::jni::NativeStub<" + traits + ", Impl>\n" +
+ " ::template Wrap<&Impl::" + info.wrapperName + ">)");
+ }
+
+ private String getLiteral(Object val, AnnotationInfo info) {
+ final Class<?> type = val.getClass();
+
+ if (type.equals(char.class) || type.equals(Character.class)) {
+ final char c = (char) val;
+ if (c >= 0x20 && c < 0x7F) {
+ return "'" + c + '\'';
+ }
+ return "u'\\u" + Integer.toHexString(0x10000 | (int) c).substring(1) + '\'';
+
+ } else if (type.equals(CharSequence.class) || type.equals(String.class)) {
+ final CharSequence str = (CharSequence) val;
+ final StringBuilder out = new StringBuilder(info.narrowChars ? "u8\"" : "u\"");
+ for (int i = 0; i < str.length(); i++) {
+ final char c = str.charAt(i);
+ if (c >= 0x20 && c < 0x7F) {
+ out.append(c);
+ } else {
+ out.append("\\u").append(Integer.toHexString(0x10000 | (int) c).substring(1));
+ }
+ }
+ return out.append('"').toString();
+ }
+
+ return String.valueOf(val);
+ }
+
+ public void generateField(AnnotatableEntity annotatedField) {
+ final Field field = annotatedField.getField();
+ final AnnotationInfo info = annotatedField.mAnnotationInfo;
+ final String uniqueName = info.wrapperName;
+ final Class<?> type = field.getType();
+
+ // Handles a peculiar case when dealing with enum types. We don't care about this field.
+ // It just gets in the way and stops our code from compiling.
+ if (field.isSynthetic() || field.getName().equals("$VALUES")) {
+ return;
+ }
+
+ final boolean isStatic = Utils.isStatic(field);
+ final boolean isFinal = Utils.isFinal(field);
+
+ if (isStatic && isFinal && (type.isPrimitive() || type.equals(String.class))) {
+ Object val = null;
+ try {
+ field.setAccessible(true);
+ val = field.get(null);
+ } catch (final IllegalAccessException e) {
+ }
+
+ if (val != null && type.isPrimitive()) {
+ // For static final primitive fields, we can use a "static const" declaration.
+ header.append(
+ "public:\n" +
+ " static const " + Utils.getNativeReturnType(type, info) +
+ ' ' + info.wrapperName + " = " + getLiteral(val, info) + ";\n" +
+ "\n");
+ return;
+
+ } else if (val != null && type.equals(String.class)) {
+ final String nativeType = info.narrowChars ? "char" : "char16_t";
+
+ header.append(
+ "public:\n" +
+ " static const " + nativeType + ' ' + info.wrapperName + "[];\n" +
+ "\n");
+
+ cpp.append(
+ "const " + nativeType + ' ' + clsName + "::" + info.wrapperName +
+ "[] = " + getLiteral(val, info) + ";\n" +
+ "\n");
+ return;
+ }
+
+ // Fall back to using accessors if we encounter an exception.
+ }
+
+ generateMember(info, field, uniqueName, type, EMPTY_CLASS_ARRAY);
+
+ final Class<?>[] getterArgs = EMPTY_CLASS_ARRAY;
+
+ header.append(
+ " " + generateDeclaration(info.wrapperName, getterArgs,
+ type, info, isStatic) + "\n" +
+ "\n");
+
+ cpp.append(
+ generateDefinition(
+ "mozilla::jni::Field<" +
+ getTraitsName(uniqueName, /* includeScope */ false) + ">::Get",
+ info.wrapperName, getterArgs, type, info, isStatic) + "\n" +
+ "\n");
+
+ if (isFinal) {
+ return;
+ }
+
+ final Class<?>[] setterArgs = new Class<?>[] { type };
+
+ header.append(
+ " " + generateDeclaration(info.wrapperName, setterArgs,
+ void.class, info, isStatic) + "\n" +
+ "\n");
+
+ cpp.append(
+ generateDefinition(
+ "mozilla::jni::Field<" +
+ getTraitsName(uniqueName, /* includeScope */ false) + ">::Set",
+ info.wrapperName, setterArgs, void.class, info, isStatic) + "\n" +
+ "\n");
+ }
+
+ public void generateConstructor(AnnotatableEntity annotatedConstructor) {
+ // Unpack the tuple and extract some useful fields from the Method..
+ final Constructor<?> method = annotatedConstructor.getConstructor();
+ final AnnotationInfo info = annotatedConstructor.mAnnotationInfo;
+ final String wrapperName = "New";
+ final String uniqueName = getUniqueMethodName(wrapperName);
+ final Class<?>[] argTypes = method.getParameterTypes();
+ final Class<?> returnType = cls;
+
+ if (method.isSynthetic()) {
+ return;
+ }
+
+ generateMember(info, method, uniqueName, returnType, argTypes);
+
+ header.append(
+ " " + generateDeclaration(wrapperName, argTypes,
+ returnType, info, /* isStatic */ true) + "\n" +
+ "\n");
+
+ cpp.append(
+ generateDefinition(
+ "mozilla::jni::Constructor<" +
+ getTraitsName(uniqueName, /* includeScope */ false) + ">::Call",
+ wrapperName, argTypes, returnType, info, /* isStatic */ true) + "\n" +
+ "\n");
+ }
+
+ public void generateMembers(Member[] members) {
+ for (Member m : members) {
+ if (!Modifier.isPublic(m.getModifiers())) {
+ continue;
+ }
+
+ String name = Utils.getMemberName(m);
+ name = name.substring(0, 1).toUpperCase() + name.substring(1);
+
+ final AnnotationInfo info = new AnnotationInfo(name,
+ /* multithread */ true, /* nothrow */ false,
+ /* narrow */ false, /* catchException */ true);
+ final AnnotatableEntity entity = new AnnotatableEntity(m, info);
+
+ if (m instanceof Constructor) {
+ generateConstructor(entity);
+ } else if (m instanceof Method) {
+ generateMethod(entity);
+ } else if (m instanceof Field) {
+ generateField(entity);
+ } else {
+ throw new IllegalArgumentException(
+ "expected member to be Constructor, Method, or Field");
+ }
+ }
+ }
+
+ public void generateClasses(final ClassWithOptions[] classes) {
+ if (classes.length == 0) {
+ return;
+ }
+
+ header.append(
+ "public:\n");
+ for (final ClassWithOptions cls : classes) {
+ // Extract "Inner" from "Outer::Inner".
+ header.append(
+ " class " + Utils.getUnqualifiedName(cls.generatedName) + ";\n");
+ }
+ header.append('\n');
+ }
+
+ /**
+ * Get the finalised bytes to go into the generated wrappers file.
+ *
+ * @return The bytes to be written to the wrappers file.
+ */
+ public String getWrapperFileContents() {
+ return cpp.toString();
+ }
+
+ /**
+ * Get the finalised bytes to go into the generated header file.
+ *
+ * @return The bytes to be written to the header file.
+ */
+ public String getHeaderFileContents() {
+ if (nativesInits.length() > 0) {
+ header.append(
+ "public:\n" +
+ " template<class Impl> class Natives;\n");
+ }
+ header.append(
+ "};\n" +
+ "\n");
+ return header.toString();
+ }
+
+ /**
+ * Get the finalised bytes to go into the generated natives header file.
+ *
+ * @return The bytes to be written to the header file.
+ */
+ public String getNativesFileContents() {
+ if (nativesInits.length() == 0) {
+ return "";
+ }
+ natives.append(
+ "public:\n" +
+ " static constexpr JNINativeMethod methods[] = {" + nativesInits + '\n' +
+ " };\n" +
+ "};\n" +
+ "\n" +
+ "template<class Impl>\n" +
+ "constexpr JNINativeMethod " + clsName + "::Natives<Impl>::methods[];\n" +
+ "\n");
+ return natives.toString();
+ }
+}
diff --git a/src/third_party/mozjs-45/build/annotationProcessors/Makefile.in b/src/third_party/mozjs-45/build/annotationProcessors/Makefile.in
new file mode 100644
index 0000000..55b455e
--- /dev/null
+++ b/src/third_party/mozjs-45/build/annotationProcessors/Makefile.in
@@ -0,0 +1,10 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+include $(topsrcdir)/config/rules.mk
+
+# Include Android specific java flags, instead of what's in rules.mk.
+include $(topsrcdir)/config/android-common.mk
+
+export:: annotationProcessors.jar
diff --git a/src/third_party/mozjs-45/build/annotationProcessors/SDKProcessor.java b/src/third_party/mozjs-45/build/annotationProcessors/SDKProcessor.java
new file mode 100644
index 0000000..8b045fa
--- /dev/null
+++ b/src/third_party/mozjs-45/build/annotationProcessors/SDKProcessor.java
@@ -0,0 +1,258 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+package org.mozilla.gecko.annotationProcessors;
+
+import com.android.tools.lint.checks.ApiLookup;
+import com.android.tools.lint.LintCliClient;
+
+import org.mozilla.gecko.annotationProcessors.classloader.AnnotatableEntity;
+import org.mozilla.gecko.annotationProcessors.classloader.ClassWithOptions;
+import org.mozilla.gecko.annotationProcessors.classloader.IterableJarLoadingURLClassLoader;
+import org.mozilla.gecko.annotationProcessors.utils.GeneratableElementIterator;
+import org.mozilla.gecko.annotationProcessors.utils.Utils;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.util.Arrays;
+import java.util.ArrayList;
+import java.util.Comparator;
+import java.util.Iterator;
+import java.util.Properties;
+import java.util.Scanner;
+import java.util.Vector;
+import java.net.URL;
+import java.net.URLClassLoader;
+
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Field;
+import java.lang.reflect.Member;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+
+public class SDKProcessor {
+ public static final String GENERATED_COMMENT =
+ "// GENERATED CODE\n" +
+ "// Generated by the Java program at /build/annotationProcessors at compile time\n" +
+ "// from annotations on Java methods. To update, change the annotations on the\n" +
+ "// corresponding Javamethods and rerun the build. Manually updating this file\n" +
+ "// will cause your build to fail.\n" +
+ "\n";
+
+ private static ApiLookup sApiLookup;
+ private static int sMaxSdkVersion;
+
+ public static void main(String[] args) throws Exception {
+ // We expect a list of jars on the commandline. If missing, whinge about it.
+ if (args.length < 5) {
+ System.err.println("Usage: java SDKProcessor sdkjar classlistfile outdir fileprefix max-sdk-version");
+ System.exit(1);
+ }
+
+ System.out.println("Processing platform bindings...");
+
+ String sdkJar = args[0];
+ Vector classes = getClassList(args[1]);
+ String outdir = args[2];
+ String generatedFilePrefix = args[3];
+ sMaxSdkVersion = Integer.parseInt(args[4]);
+
+ LintCliClient lintClient = new LintCliClient();
+ sApiLookup = ApiLookup.get(lintClient);
+
+ // Start the clock!
+ long s = System.currentTimeMillis();
+
+ // Get an iterator over the classes in the jar files given...
+ // Iterator<ClassWithOptions> jarClassIterator = IterableJarLoadingURLClassLoader.getIteratorOverJars(args);
+
+ StringBuilder headerFile = new StringBuilder(GENERATED_COMMENT);
+ headerFile.append(
+ "#ifndef " + generatedFilePrefix + "_h__\n" +
+ "#define " + generatedFilePrefix + "_h__\n" +
+ "\n" +
+ "#include \"mozilla/jni/Refs.h\"\n" +
+ "\n" +
+ "namespace mozilla {\n" +
+ "namespace widget {\n" +
+ "namespace sdk {\n" +
+ "\n");
+
+ StringBuilder implementationFile = new StringBuilder(GENERATED_COMMENT);
+ implementationFile.append(
+ "#include \"" + generatedFilePrefix + ".h\"\n" +
+ "#include \"mozilla/jni/Accessors.h\"\n" +
+ "\n" +
+ "namespace mozilla {\n" +
+ "namespace widget {\n" +
+ "namespace sdk {\n" +
+ "\n");
+
+ // Used to track the calls to the various class-specific initialisation functions.
+ ClassLoader loader = null;
+ try {
+ loader = URLClassLoader.newInstance(new URL[] { new URL("file://" + sdkJar) },
+ SDKProcessor.class.getClassLoader());
+ } catch (Exception e) {
+ throw new RuntimeException(e.toString());
+ }
+
+ for (Iterator<String> i = classes.iterator(); i.hasNext(); ) {
+ String className = i.next();
+ System.out.println("Looking up: " + className);
+
+ generateClass(Class.forName(className, true, loader),
+ implementationFile,
+ headerFile);
+ }
+
+ implementationFile.append(
+ "} /* sdk */\n" +
+ "} /* widget */\n" +
+ "} /* mozilla */\n");
+
+ headerFile.append(
+ "} /* sdk */\n" +
+ "} /* widget */\n" +
+ "} /* mozilla */\n" +
+ "#endif\n");
+
+ writeOutputFiles(outdir, generatedFilePrefix, headerFile, implementationFile);
+ long e = System.currentTimeMillis();
+ System.out.println("SDK processing complete in " + (e - s) + "ms");
+ }
+
+ private static int getAPIVersion(Class<?> cls, Member m) {
+ if (m instanceof Method || m instanceof Constructor) {
+ return sApiLookup.getCallVersion(
+ cls.getName().replace('.', '/'),
+ Utils.getMemberName(m),
+ Utils.getSignature(m));
+ } else if (m instanceof Field) {
+ return sApiLookup.getFieldVersion(
+ Utils.getClassDescriptor(m.getDeclaringClass()), m.getName());
+ } else {
+ throw new IllegalArgumentException("expected member to be Method, Constructor, or Field");
+ }
+ }
+
+ private static Member[] sortAndFilterMembers(Class<?> cls, Member[] members) {
+ Arrays.sort(members, new Comparator<Member>() {
+ @Override
+ public int compare(Member a, Member b) {
+ return a.getName().compareTo(b.getName());
+ }
+ });
+
+ ArrayList<Member> list = new ArrayList<>();
+ for (Member m : members) {
+ // Sometimes (e.g. Bundle) has methods that moved to/from a superclass in a later SDK
+ // version, so we check for both classes and see if we can find a minimum SDK version.
+ int version = getAPIVersion(cls, m);
+ final int version2 = getAPIVersion(m.getDeclaringClass(), m);
+ if (version2 > 0 && version2 < version) {
+ version = version2;
+ }
+ if (version > sMaxSdkVersion) {
+ System.out.println("Skipping " + m.getDeclaringClass().getName() + "." + m.getName() +
+ ", version " + version + " > " + sMaxSdkVersion);
+ continue;
+ }
+
+ // Sometimes (e.g. KeyEvent) a field can appear in both a class and a superclass. In
+ // that case we want to filter out the version that appears in the superclass, or
+ // we'll have bindings with duplicate names.
+ try {
+ if (m instanceof Field && !m.equals(cls.getField(m.getName()))) {
+ // m is a field in a superclass that has been hidden by
+ // a field with the same name in a subclass.
+ System.out.println("Skipping " + m.getName() +
+ " from " + m.getDeclaringClass());
+ continue;
+ }
+ } catch (final NoSuchFieldException e) {
+ }
+
+ list.add(m);
+ }
+
+ return list.toArray(new Member[list.size()]);
+ }
+
+ private static void generateClass(Class<?> clazz,
+ StringBuilder implementationFile,
+ StringBuilder headerFile) {
+ String generatedName = clazz.getSimpleName();
+
+ CodeGenerator generator = new CodeGenerator(new ClassWithOptions(clazz, generatedName));
+
+ generator.generateMembers(sortAndFilterMembers(clazz, clazz.getConstructors()));
+ generator.generateMembers(sortAndFilterMembers(clazz, clazz.getMethods()));
+ generator.generateMembers(sortAndFilterMembers(clazz, clazz.getFields()));
+
+ headerFile.append(generator.getHeaderFileContents());
+ implementationFile.append(generator.getWrapperFileContents());
+ }
+
+ private static Vector<String> getClassList(String path) {
+ Scanner scanner = null;
+ try {
+ scanner = new Scanner(new FileInputStream(path));
+
+ Vector lines = new Vector();
+ while (scanner.hasNextLine()) {
+ lines.add(scanner.nextLine());
+ }
+ return lines;
+ } catch (Exception e) {
+ System.out.println(e.toString());
+ return null;
+ } finally {
+ if (scanner != null) {
+ scanner.close();
+ }
+ }
+ }
+
+ private static void writeOutputFiles(String aOutputDir, String aPrefix, StringBuilder aHeaderFile,
+ StringBuilder aImplementationFile) {
+ FileOutputStream implStream = null;
+ try {
+ implStream = new FileOutputStream(new File(aOutputDir, aPrefix + ".cpp"));
+ implStream.write(aImplementationFile.toString().getBytes());
+ } catch (IOException e) {
+ System.err.println("Unable to write " + aOutputDir + ". Perhaps a permissions issue?");
+ e.printStackTrace(System.err);
+ } finally {
+ if (implStream != null) {
+ try {
+ implStream.close();
+ } catch (IOException e) {
+ System.err.println("Unable to close implStream due to "+e);
+ e.printStackTrace(System.err);
+ }
+ }
+ }
+
+ FileOutputStream headerStream = null;
+ try {
+ headerStream = new FileOutputStream(new File(aOutputDir, aPrefix + ".h"));
+ headerStream.write(aHeaderFile.toString().getBytes());
+ } catch (IOException e) {
+ System.err.println("Unable to write " + aOutputDir + ". Perhaps a permissions issue?");
+ e.printStackTrace(System.err);
+ } finally {
+ if (headerStream != null) {
+ try {
+ headerStream.close();
+ } catch (IOException e) {
+ System.err.println("Unable to close headerStream due to "+e);
+ e.printStackTrace(System.err);
+ }
+ }
+ }
+ }
+}
diff --git a/src/third_party/mozjs-45/build/annotationProcessors/classloader/AnnotatableEntity.java b/src/third_party/mozjs-45/build/annotationProcessors/classloader/AnnotatableEntity.java
new file mode 100644
index 0000000..b11a6c4
--- /dev/null
+++ b/src/third_party/mozjs-45/build/annotationProcessors/classloader/AnnotatableEntity.java
@@ -0,0 +1,62 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+package org.mozilla.gecko.annotationProcessors.classloader;
+
+import org.mozilla.gecko.annotationProcessors.AnnotationInfo;
+
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Field;
+import java.lang.reflect.Member;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+
+/**
+ * Union type to hold either a method, field, or ctor. Allows us to iterate "The generatable stuff", despite
+ * the fact that such things can be of either flavour.
+ */
+public class AnnotatableEntity {
+ public enum ENTITY_TYPE {METHOD, NATIVE, FIELD, CONSTRUCTOR}
+
+ private final Member mMember;
+ public final ENTITY_TYPE mEntityType;
+
+ public final AnnotationInfo mAnnotationInfo;
+
+ public AnnotatableEntity(Member aObject, AnnotationInfo aAnnotationInfo) {
+ mMember = aObject;
+ mAnnotationInfo = aAnnotationInfo;
+
+ if (aObject instanceof Method) {
+ if (Modifier.isNative(aObject.getModifiers())) {
+ mEntityType = ENTITY_TYPE.NATIVE;
+ } else {
+ mEntityType = ENTITY_TYPE.METHOD;
+ }
+ } else if (aObject instanceof Field) {
+ mEntityType = ENTITY_TYPE.FIELD;
+ } else {
+ mEntityType = ENTITY_TYPE.CONSTRUCTOR;
+ }
+ }
+
+ public Method getMethod() {
+ if (mEntityType != ENTITY_TYPE.METHOD && mEntityType != ENTITY_TYPE.NATIVE) {
+ throw new UnsupportedOperationException("Attempt to cast to unsupported member type.");
+ }
+ return (Method) mMember;
+ }
+ public Field getField() {
+ if (mEntityType != ENTITY_TYPE.FIELD) {
+ throw new UnsupportedOperationException("Attempt to cast to unsupported member type.");
+ }
+ return (Field) mMember;
+ }
+ public Constructor<?> getConstructor() {
+ if (mEntityType != ENTITY_TYPE.CONSTRUCTOR) {
+ throw new UnsupportedOperationException("Attempt to cast to unsupported member type.");
+ }
+ return (Constructor<?>) mMember;
+ }
+}
diff --git a/src/third_party/mozjs-45/build/annotationProcessors/classloader/ClassWithOptions.java b/src/third_party/mozjs-45/build/annotationProcessors/classloader/ClassWithOptions.java
new file mode 100644
index 0000000..070cff8
--- /dev/null
+++ b/src/third_party/mozjs-45/build/annotationProcessors/classloader/ClassWithOptions.java
@@ -0,0 +1,15 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+package org.mozilla.gecko.annotationProcessors.classloader;
+
+public class ClassWithOptions {
+ public final Class<?> wrappedClass;
+ public final String generatedName;
+
+ public ClassWithOptions(Class<?> someClass, String name) {
+ wrappedClass = someClass;
+ generatedName = name;
+ }
+}
diff --git a/src/third_party/mozjs-45/build/annotationProcessors/classloader/IterableJarLoadingURLClassLoader.java b/src/third_party/mozjs-45/build/annotationProcessors/classloader/IterableJarLoadingURLClassLoader.java
new file mode 100644
index 0000000..7e74399
--- /dev/null
+++ b/src/third_party/mozjs-45/build/annotationProcessors/classloader/IterableJarLoadingURLClassLoader.java
@@ -0,0 +1,75 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+package org.mozilla.gecko.annotationProcessors.classloader;
+
+import java.io.File;
+import java.io.IOException;
+import java.net.URL;
+import java.net.URLClassLoader;
+import java.util.Collections;
+import java.util.Enumeration;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.jar.JarEntry;
+import java.util.jar.JarFile;
+
+/**
+ * A classloader which can be initialised with a list of jar files and which can provide an iterator
+ * over the top level classes in the jar files it was initialised with.
+ * classNames is kept sorted to ensure iteration order is consistent across program invocations.
+ * Otherwise, we'd forever be reporting the outdatedness of the generated code as we permute its
+ * contents.
+ */
+public class IterableJarLoadingURLClassLoader extends URLClassLoader {
+ LinkedList<String> classNames = new LinkedList<String>();
+
+ /**
+ * Create an instance and return its iterator. Provides an iterator over the classes in the jar
+ * files provided as arguments.
+ * Inner classes are not supported.
+ *
+ * @param args A list of jar file names an iterator over the classes of which is desired.
+ * @return An iterator over the top level classes in the jar files provided, in arbitrary order.
+ */
+ public static Iterator<ClassWithOptions> getIteratorOverJars(String[] args) {
+ URL[] urlArray = new URL[args.length];
+ LinkedList<String> aClassNames = new LinkedList<String>();
+
+ for (int i = 0; i < args.length; i++) {
+ try {
+ urlArray[i] = (new File(args[i])).toURI().toURL();
+
+ Enumeration<JarEntry> entries = new JarFile(args[i]).entries();
+ while (entries.hasMoreElements()) {
+ JarEntry e = entries.nextElement();
+ String fName = e.getName();
+ if (!fName.endsWith(".class")) {
+ continue;
+ }
+ final String className = fName.substring(0, fName.length() - 6).replace('/', '.');
+
+ aClassNames.add(className);
+ }
+ } catch (IOException e) {
+ System.err.println("Error loading jar file \"" + args[i] + '"');
+ e.printStackTrace(System.err);
+ }
+ }
+ Collections.sort(aClassNames);
+ return new JarClassIterator(new IterableJarLoadingURLClassLoader(urlArray, aClassNames));
+ }
+
+ /**
+ * Constructs a classloader capable of loading all classes given as URLs in urls. Used by static
+ * method above.
+ *
+ * @param urls URLs for all classes the new instance shall be capable of loading.
+ * @param aClassNames A list of names of the classes this instance shall be capable of loading.
+ */
+ protected IterableJarLoadingURLClassLoader(URL[] urls, LinkedList<String> aClassNames) {// Array to populate with URLs for each class in the given jars.
+ super(urls);
+ classNames = aClassNames;
+ }
+}
diff --git a/src/third_party/mozjs-45/build/annotationProcessors/classloader/JarClassIterator.java b/src/third_party/mozjs-45/build/annotationProcessors/classloader/JarClassIterator.java
new file mode 100644
index 0000000..452de81
--- /dev/null
+++ b/src/third_party/mozjs-45/build/annotationProcessors/classloader/JarClassIterator.java
@@ -0,0 +1,84 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+package org.mozilla.gecko.annotationProcessors.classloader;
+
+import java.util.Iterator;
+
+/**
+ * Class for iterating over an IterableJarLoadingURLClassLoader's classes.
+ *
+ * This class is not thread safe: use it only from a single thread.
+ */
+public class JarClassIterator implements Iterator<ClassWithOptions> {
+ private IterableJarLoadingURLClassLoader mTarget;
+ private Iterator<String> mTargetClassListIterator;
+
+ private ClassWithOptions lookAhead;
+
+ public JarClassIterator(IterableJarLoadingURLClassLoader aTarget) {
+ mTarget = aTarget;
+ mTargetClassListIterator = aTarget.classNames.iterator();
+ }
+
+ @Override
+ public boolean hasNext() {
+ return fillLookAheadIfPossible();
+ }
+
+ @Override
+ public ClassWithOptions next() {
+ if (!fillLookAheadIfPossible()) {
+ throw new IllegalStateException("Failed to look ahead in next()!");
+ }
+ ClassWithOptions next = lookAhead;
+ lookAhead = null;
+ return next;
+ }
+
+ private boolean fillLookAheadIfPossible() {
+ if (lookAhead != null) {
+ return true;
+ }
+
+ if (!mTargetClassListIterator.hasNext()) {
+ return false;
+ }
+
+ String className = mTargetClassListIterator.next();
+ try {
+ Class<?> ret = mTarget.loadClass(className);
+
+ // Incremental builds can leave stale classfiles in the jar. Such classfiles will cause
+ // an exception at this point. We can safely ignore these classes - they cannot possibly
+ // ever be loaded as they conflict with their parent class and will be killed by
+ // Proguard later on anyway.
+ final Class<?> enclosingClass;
+ try {
+ enclosingClass = ret.getEnclosingClass();
+ } catch (IncompatibleClassChangeError e) {
+ return fillLookAheadIfPossible();
+ }
+
+ if (enclosingClass != null) {
+ // Anonymous inner class - unsupported.
+ // Or named inner class, which will be processed when we process the outer class.
+ return fillLookAheadIfPossible();
+ }
+
+ lookAhead = new ClassWithOptions(ret, ret.getSimpleName());
+ return true;
+ } catch (ClassNotFoundException e) {
+ System.err.println("Unable to enumerate class: " + className + ". Corrupted jar file?");
+ e.printStackTrace();
+ System.exit(2);
+ }
+ return false;
+ }
+
+ @Override
+ public void remove() {
+ throw new UnsupportedOperationException("Removal of classes from iterator not supported.");
+ }
+}
diff --git a/src/third_party/mozjs-45/build/annotationProcessors/moz.build b/src/third_party/mozjs-45/build/annotationProcessors/moz.build
new file mode 100644
index 0000000..f2200eb
--- /dev/null
+++ b/src/third_party/mozjs-45/build/annotationProcessors/moz.build
@@ -0,0 +1,24 @@
+# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
+# vim: set filetype=python:
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+jar = add_java_jar('annotationProcessors')
+jar.sources += [
+ 'AnnotationInfo.java',
+ 'AnnotationProcessor.java',
+ 'classloader/AnnotatableEntity.java',
+ 'classloader/ClassWithOptions.java',
+ 'classloader/IterableJarLoadingURLClassLoader.java',
+ 'classloader/JarClassIterator.java',
+ 'CodeGenerator.java',
+ 'SDKProcessor.java',
+ 'utils/AlphabeticAnnotatableEntityComparator.java',
+ 'utils/GeneratableElementIterator.java',
+ 'utils/Utils.java',
+]
+jar.extra_jars += [
+ CONFIG['ANDROID_TOOLS'] + '/lib/lint.jar',
+ CONFIG['ANDROID_TOOLS'] + '/lib/lint-checks.jar',
+]
diff --git a/src/third_party/mozjs-45/build/annotationProcessors/utils/AlphabeticAnnotatableEntityComparator.java b/src/third_party/mozjs-45/build/annotationProcessors/utils/AlphabeticAnnotatableEntityComparator.java
new file mode 100644
index 0000000..2ee2ae5
--- /dev/null
+++ b/src/third_party/mozjs-45/build/annotationProcessors/utils/AlphabeticAnnotatableEntityComparator.java
@@ -0,0 +1,81 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+package org.mozilla.gecko.annotationProcessors.utils;
+
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Field;
+import java.lang.reflect.Member;
+import java.lang.reflect.Method;
+import java.util.Comparator;
+
+public class AlphabeticAnnotatableEntityComparator<T extends Member> implements Comparator<T> {
+ @Override
+ public int compare(T aLhs, T aRhs) {
+ // Constructors, Methods, Fields.
+ boolean lIsConstructor = aLhs instanceof Constructor;
+ boolean rIsConstructor = aRhs instanceof Constructor;
+ boolean lIsMethod = aLhs instanceof Method;
+ boolean rIsField = aRhs instanceof Field;
+
+ if (lIsConstructor) {
+ if (!rIsConstructor) {
+ return -1;
+ }
+ } else if (lIsMethod) {
+ if (rIsConstructor) {
+ return 1;
+ } else if (rIsField) {
+ return -1;
+ }
+ } else {
+ if (!rIsField) {
+ return 1;
+ }
+ }
+
+ // Verify these objects are the same type and cast them.
+ if (aLhs instanceof Method) {
+ return compare((Method) aLhs, (Method) aRhs);
+ } else if (aLhs instanceof Field) {
+ return compare((Field) aLhs, (Field) aRhs);
+ } else {
+ return compare((Constructor) aLhs, (Constructor) aRhs);
+ }
+ }
+
+ // Alas, the type system fails us.
+ private static int compare(Method aLhs, Method aRhs) {
+ // Initially, attempt to differentiate the methods be name alone..
+ String lName = aLhs.getName();
+ String rName = aRhs.getName();
+
+ int ret = lName.compareTo(rName);
+ if (ret != 0) {
+ return ret;
+ }
+
+ // The names were the same, so we need to compare signatures to find their uniqueness..
+ lName = Utils.getSignature(aLhs);
+ rName = Utils.getSignature(aRhs);
+
+ return lName.compareTo(rName);
+ }
+
+ private static int compare(Constructor<?> aLhs, Constructor<?> aRhs) {
+ // The names will be the same, so we need to compare signatures to find their uniqueness..
+ String lName = Utils.getSignature(aLhs);
+ String rName = Utils.getSignature(aRhs);
+
+ return lName.compareTo(rName);
+ }
+
+ private static int compare(Field aLhs, Field aRhs) {
+ // Compare field names..
+ String lName = aLhs.getName();
+ String rName = aRhs.getName();
+
+ return lName.compareTo(rName);
+ }
+}
diff --git a/src/third_party/mozjs-45/build/annotationProcessors/utils/GeneratableElementIterator.java b/src/third_party/mozjs-45/build/annotationProcessors/utils/GeneratableElementIterator.java
new file mode 100644
index 0000000..4f27f2d
--- /dev/null
+++ b/src/third_party/mozjs-45/build/annotationProcessors/utils/GeneratableElementIterator.java
@@ -0,0 +1,220 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+package org.mozilla.gecko.annotationProcessors.utils;
+
+import org.mozilla.gecko.annotationProcessors.AnnotationInfo;
+import org.mozilla.gecko.annotationProcessors.classloader.AnnotatableEntity;
+import org.mozilla.gecko.annotationProcessors.classloader.ClassWithOptions;
+
+import java.lang.annotation.Annotation;
+import java.lang.reflect.AnnotatedElement;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Member;
+import java.lang.reflect.Method;
+import java.util.Arrays;
+import java.util.Comparator;
+import java.util.Iterator;
+
+/**
+ * Iterator over the methods in a given method list which have the WrappedJNIMethod
+ * annotation. Returns an object containing both the annotation (Which may contain interesting
+ * parameters) and the argument.
+ */
+public class GeneratableElementIterator implements Iterator<AnnotatableEntity> {
+ private final ClassWithOptions mClass;
+ private final Member[] mObjects;
+ private AnnotatableEntity mNextReturnValue;
+ private int mElementIndex;
+
+ private boolean mIterateEveryEntry;
+
+ public GeneratableElementIterator(ClassWithOptions annotatedClass) {
+ mClass = annotatedClass;
+
+ final Class<?> aClass = annotatedClass.wrappedClass;
+ // Get all the elements of this class as AccessibleObjects.
+ Member[] aMethods = aClass.getDeclaredMethods();
+ Member[] aFields = aClass.getDeclaredFields();
+ Member[] aCtors = aClass.getDeclaredConstructors();
+
+ // Shove them all into one buffer.
+ Member[] objs = new Member[aMethods.length + aFields.length + aCtors.length];
+
+ int offset = 0;
+ System.arraycopy(aMethods, 0, objs, 0, aMethods.length);
+ offset += aMethods.length;
+ System.arraycopy(aFields, 0, objs, offset, aFields.length);
+ offset += aFields.length;
+ System.arraycopy(aCtors, 0, objs, offset, aCtors.length);
+
+ // Sort the elements to ensure determinism.
+ Arrays.sort(objs, new AlphabeticAnnotatableEntityComparator<Member>());
+ mObjects = objs;
+
+ // Check for "Wrap ALL the things" flag.
+ for (Annotation annotation : aClass.getDeclaredAnnotations()) {
+ final String annotationTypeName = annotation.annotationType().getName();
+ if (annotationTypeName.equals("org.mozilla.gecko.annotation.WrapForJNI")) {
+ mIterateEveryEntry = true;
+ break;
+ }
+ }
+
+ findNextValue();
+ }
+
+ private Class<?>[] getFilteredInnerClasses() {
+ // Go through all inner classes and see which ones we want to generate.
+ final Class<?>[] candidates = mClass.wrappedClass.getDeclaredClasses();
+ int count = 0;
+
+ for (int i = 0; i < candidates.length; ++i) {
+ final GeneratableElementIterator testIterator
+ = new GeneratableElementIterator(new ClassWithOptions(candidates[i], null));
+ if (testIterator.hasNext()
+ || testIterator.getFilteredInnerClasses() != null) {
+ count++;
+ continue;
+ }
+ // Clear out ones that don't match.
+ candidates[i] = null;
+ }
+ return count > 0 ? candidates : null;
+ }
+
+ public ClassWithOptions[] getInnerClasses() {
+ final Class<?>[] candidates = getFilteredInnerClasses();
+ if (candidates == null) {
+ return new ClassWithOptions[0];
+ }
+
+ int count = 0;
+ for (Class<?> candidate : candidates) {
+ if (candidate != null) {
+ count++;
+ }
+ }
+
+ final ClassWithOptions[] ret = new ClassWithOptions[count];
+ count = 0;
+ for (Class<?> candidate : candidates) {
+ if (candidate != null) {
+ ret[count++] = new ClassWithOptions(
+ candidate, mClass.generatedName + "::" + candidate.getSimpleName());
+ }
+ }
+ assert ret.length == count;
+
+ Arrays.sort(ret, new Comparator<ClassWithOptions>() {
+ @Override public int compare(ClassWithOptions lhs, ClassWithOptions rhs) {
+ return lhs.generatedName.compareTo(rhs.generatedName);
+ }
+ });
+ return ret;
+ }
+
+ /**
+ * Find and cache the next appropriately annotated method, plus the annotation parameter, if
+ * one exists. Otherwise cache null, so hasNext returns false.
+ */
+ private void findNextValue() {
+ while (mElementIndex < mObjects.length) {
+ Member candidateElement = mObjects[mElementIndex];
+ mElementIndex++;
+ for (Annotation annotation : ((AnnotatedElement) candidateElement).getDeclaredAnnotations()) {
+ // WrappedJNIMethod has parameters. Use Reflection to obtain them.
+ Class<? extends Annotation> annotationType = annotation.annotationType();
+ final String annotationTypeName = annotationType.getName();
+ if (annotationTypeName.equals("org.mozilla.gecko.annotation.WrapForJNI")) {
+ String stubName = null;
+ boolean isMultithreadedStub = false;
+ boolean noThrow = false;
+ boolean narrowChars = false;
+ boolean catchException = false;
+ try {
+ // Determine the explicitly-given name of the stub to generate, if any.
+ final Method stubNameMethod = annotationType.getDeclaredMethod("stubName");
+ stubNameMethod.setAccessible(true);
+ stubName = (String) stubNameMethod.invoke(annotation);
+
+ // Determine if the generated stub is to allow calls from multiple threads.
+ final Method multithreadedStubMethod = annotationType.getDeclaredMethod("allowMultithread");
+ multithreadedStubMethod.setAccessible(true);
+ isMultithreadedStub = (Boolean) multithreadedStubMethod.invoke(annotation);
+
+ // Determine if ignoring exceptions
+ final Method noThrowMethod = annotationType.getDeclaredMethod("noThrow");
+ noThrowMethod.setAccessible(true);
+ noThrow = (Boolean) noThrowMethod.invoke(annotation);
+
+ // Determine if strings should be wide or narrow
+ final Method narrowCharsMethod = annotationType.getDeclaredMethod("narrowChars");
+ narrowCharsMethod.setAccessible(true);
+ narrowChars = (Boolean) narrowCharsMethod.invoke(annotation);
+
+ // Determine if we should catch exceptions
+ final Method catchExceptionMethod = annotationType.getDeclaredMethod("catchException");
+ catchExceptionMethod.setAccessible(true);
+ catchException = (Boolean) catchExceptionMethod.invoke(annotation);
+
+ } catch (NoSuchMethodException e) {
+ System.err.println("Unable to find expected field on WrapForJNI annotation. Did the signature change?");
+ e.printStackTrace(System.err);
+ System.exit(3);
+ } catch (IllegalAccessException e) {
+ System.err.println("IllegalAccessException reading fields on WrapForJNI annotation. Seems the semantics of Reflection have changed...");
+ e.printStackTrace(System.err);
+ System.exit(4);
+ } catch (InvocationTargetException e) {
+ System.err.println("InvocationTargetException reading fields on WrapForJNI annotation. This really shouldn't happen.");
+ e.printStackTrace(System.err);
+ System.exit(5);
+ }
+
+ // If the method name was not explicitly given in the annotation generate one...
+ if (stubName.isEmpty()) {
+ stubName = Utils.getNativeName(candidateElement);
+ }
+
+ AnnotationInfo annotationInfo = new AnnotationInfo(
+ stubName, isMultithreadedStub, noThrow, narrowChars, catchException);
+ mNextReturnValue = new AnnotatableEntity(candidateElement, annotationInfo);
+ return;
+ }
+ }
+
+ // If no annotation found, we might be expected to generate anyway
+ // using default arguments, thanks to the "Generate everything" annotation.
+ if (mIterateEveryEntry) {
+ AnnotationInfo annotationInfo = new AnnotationInfo(
+ Utils.getNativeName(candidateElement),
+ /* multithreaded */ true,
+ /* noThrow */ false,
+ /* narrowChars */ false,
+ /* catchException */ false);
+ mNextReturnValue = new AnnotatableEntity(candidateElement, annotationInfo);
+ return;
+ }
+ }
+ mNextReturnValue = null;
+ }
+
+ @Override
+ public boolean hasNext() {
+ return mNextReturnValue != null;
+ }
+
+ @Override
+ public AnnotatableEntity next() {
+ AnnotatableEntity ret = mNextReturnValue;
+ findNextValue();
+ return ret;
+ }
+
+ @Override
+ public void remove() {
+ throw new UnsupportedOperationException("Removal of methods from GeneratableElementIterator not supported.");
+ }
+}
diff --git a/src/third_party/mozjs-45/build/annotationProcessors/utils/Utils.java b/src/third_party/mozjs-45/build/annotationProcessors/utils/Utils.java
new file mode 100644
index 0000000..0e96f72
--- /dev/null
+++ b/src/third_party/mozjs-45/build/annotationProcessors/utils/Utils.java
@@ -0,0 +1,251 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+package org.mozilla.gecko.annotationProcessors.utils;
+
+import org.mozilla.gecko.annotationProcessors.AnnotationInfo;
+
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Field;
+import java.lang.reflect.Member;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.util.HashMap;
+
+/**
+ * A collection of utility methods used by CodeGenerator. Largely used for translating types.
+ */
+public class Utils {
+
+ // A collection of lookup tables to simplify the functions to follow...
+ private static final HashMap<String, String> NATIVE_TYPES = new HashMap<String, String>();
+
+ static {
+ NATIVE_TYPES.put("void", "void");
+ NATIVE_TYPES.put("boolean", "bool");
+ NATIVE_TYPES.put("byte", "int8_t");
+ NATIVE_TYPES.put("char", "char16_t");
+ NATIVE_TYPES.put("short", "int16_t");
+ NATIVE_TYPES.put("int", "int32_t");
+ NATIVE_TYPES.put("long", "int64_t");
+ NATIVE_TYPES.put("float", "float");
+ NATIVE_TYPES.put("double", "double");
+ }
+
+ private static final HashMap<String, String> NATIVE_ARRAY_TYPES = new HashMap<String, String>();
+
+ static {
+ NATIVE_ARRAY_TYPES.put("boolean", "mozilla::jni::BooleanArray");
+ NATIVE_ARRAY_TYPES.put("byte", "mozilla::jni::ByteArray");
+ NATIVE_ARRAY_TYPES.put("char", "mozilla::jni::CharArray");
+ NATIVE_ARRAY_TYPES.put("short", "mozilla::jni::ShortArray");
+ NATIVE_ARRAY_TYPES.put("int", "mozilla::jni::IntArray");
+ NATIVE_ARRAY_TYPES.put("long", "mozilla::jni::LongArray");
+ NATIVE_ARRAY_TYPES.put("float", "mozilla::jni::FloatArray");
+ NATIVE_ARRAY_TYPES.put("double", "mozilla::jni::DoubleArray");
+ }
+
+ private static final HashMap<String, String> CLASS_DESCRIPTORS = new HashMap<String, String>();
+
+ static {
+ CLASS_DESCRIPTORS.put("void", "V");
+ CLASS_DESCRIPTORS.put("boolean", "Z");
+ CLASS_DESCRIPTORS.put("byte", "B");
+ CLASS_DESCRIPTORS.put("char", "C");
+ CLASS_DESCRIPTORS.put("short", "S");
+ CLASS_DESCRIPTORS.put("int", "I");
+ CLASS_DESCRIPTORS.put("long", "J");
+ CLASS_DESCRIPTORS.put("float", "F");
+ CLASS_DESCRIPTORS.put("double", "D");
+ }
+
+ /**
+ * Get the C++ type corresponding to the provided type parameter.
+ *
+ * @param type Class to determine the corresponding JNI type for.
+ * @return C++ type as a String
+ */
+ public static String getNativeParameterType(Class<?> type, AnnotationInfo info) {
+ final String name = type.getName().replace('.', '/');
+
+ if (NATIVE_TYPES.containsKey(name)) {
+ return NATIVE_TYPES.get(name);
+ }
+
+ if (type.isArray()) {
+ final String compName = type.getComponentType().getName();
+ if (NATIVE_ARRAY_TYPES.containsKey(compName)) {
+ return NATIVE_ARRAY_TYPES.get(compName) + "::Param";
+ }
+ return "mozilla::jni::ObjectArray::Param";
+ }
+
+ if (type.equals(String.class) || type.equals(CharSequence.class)) {
+ return "mozilla::jni::String::Param";
+ }
+
+ if (type.equals(Class.class)) {
+ // You're doing reflection on Java objects from inside C, returning Class objects
+ // to C, generating the corresponding code using this Java program. Really?!
+ return "mozilla::jni::ClassObject::Param";
+ }
+
+ if (type.equals(Throwable.class)) {
+ return "mozilla::jni::Throwable::Param";
+ }
+
+ return "mozilla::jni::Object::Param";
+ }
+
+ public static String getNativeReturnType(Class<?> type, AnnotationInfo info) {
+ final String name = type.getName().replace('.', '/');
+
+ if (NATIVE_TYPES.containsKey(name)) {
+ return NATIVE_TYPES.get(name);
+ }
+
+ if (type.isArray()) {
+ final String compName = type.getComponentType().getName();
+ if (NATIVE_ARRAY_TYPES.containsKey(compName)) {
+ return NATIVE_ARRAY_TYPES.get(compName) + "::LocalRef";
+ }
+ return "mozilla::jni::ObjectArray::LocalRef";
+ }
+
+ if (type.equals(String.class)) {
+ return "mozilla::jni::String::LocalRef";
+ }
+
+ if (type.equals(Class.class)) {
+ // You're doing reflection on Java objects from inside C, returning Class objects
+ // to C, generating the corresponding code using this Java program. Really?!
+ return "mozilla::jni::ClassObject::LocalRef";
+ }
+
+ if (type.equals(Throwable.class)) {
+ return "mozilla::jni::Throwable::LocalRef";
+ }
+
+ return "mozilla::jni::Object::LocalRef";
+ }
+
+ /**
+ * Get the JNI class descriptor corresponding to the provided type parameter.
+ *
+ * @param type Class to determine the corresponding JNI descriptor for.
+ * @return Class descripor as a String
+ */
+ public static String getClassDescriptor(Class<?> type) {
+ final String name = type.getName().replace('.', '/');
+
+ if (CLASS_DESCRIPTORS.containsKey(name)) {
+ return CLASS_DESCRIPTORS.get(name);
+ }
+
+ if (type.isArray()) {
+ // Array names are already in class descriptor form.
+ return name;
+ }
+
+ return "L" + name + ';';
+ }
+
+ /**
+ * Get the JNI signaure for a member.
+ *
+ * @param member Member to get the signature for.
+ * @return JNI signature as a string
+ */
+ public static String getSignature(Member member) {
+ return member instanceof Field ? getSignature((Field) member) :
+ member instanceof Method ? getSignature((Method) member) :
+ getSignature((Constructor<?>) member);
+ }
+
+ /**
+ * Get the JNI signaure for a field.
+ *
+ * @param member Field to get the signature for.
+ * @return JNI signature as a string
+ */
+ public static String getSignature(Field member) {
+ return getClassDescriptor(member.getType());
+ }
+
+ private static String getSignature(Class<?>[] args, Class<?> ret) {
+ final StringBuilder sig = new StringBuilder("(");
+ for (int i = 0; i < args.length; i++) {
+ sig.append(getClassDescriptor(args[i]));
+ }
+ return sig.append(')').append(getClassDescriptor(ret)).toString();
+ }
+
+ /**
+ * Get the JNI signaure for a method.
+ *
+ * @param member Method to get the signature for.
+ * @return JNI signature as a string
+ */
+ public static String getSignature(Method member) {
+ return getSignature(member.getParameterTypes(), member.getReturnType());
+ }
+
+ /**
+ * Get the JNI signaure for a constructor.
+ *
+ * @param member Constructor to get the signature for.
+ * @return JNI signature as a string
+ */
+ public static String getSignature(Constructor<?> member) {
+ return getSignature(member.getParameterTypes(), void.class);
+ }
+
+ /**
+ * Get the C++ name for a member.
+ *
+ * @param member Member to get the name for.
+ * @return JNI name as a string
+ */
+ public static String getNativeName(Member member) {
+ final String name = getMemberName(member);
+ return name.substring(0, 1).toUpperCase() + name.substring(1);
+ }
+
+ /**
+ * Get the JNI name for a member.
+ *
+ * @param member Member to get the name for.
+ * @return JNI name as a string
+ */
+ public static String getMemberName(Member member) {
+ if (member instanceof Constructor) {
+ return "<init>";
+ }
+ return member.getName();
+ }
+
+ public static String getUnqualifiedName(String name) {
+ return name.substring(name.lastIndexOf(':') + 1);
+ }
+
+ /**
+ * Determine if a member is declared static.
+ *
+ * @param member The Member to check.
+ * @return true if the member is declared static, false otherwise.
+ */
+ public static boolean isStatic(final Member member) {
+ return Modifier.isStatic(member.getModifiers());
+ }
+
+ /**
+ * Determine if a member is declared final.
+ *
+ * @param member The Member to check.
+ * @return true if the member is declared final, false otherwise.
+ */
+ public static boolean isFinal(final Member member) {
+ return Modifier.isFinal(member.getModifiers());
+ }
+}
diff --git a/src/third_party/mozjs-45/build/appini_header.py b/src/third_party/mozjs-45/build/appini_header.py
new file mode 100644
index 0000000..d637d5e
--- /dev/null
+++ b/src/third_party/mozjs-45/build/appini_header.py
@@ -0,0 +1,60 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+'''Parses a given application.ini file and outputs the corresponding
+ XULAppData structure as a C++ header file'''
+
+import ConfigParser
+import sys
+
+def main(file):
+ config = ConfigParser.RawConfigParser()
+ config.read(file)
+ flags = set()
+ try:
+ if config.getint('XRE', 'EnableProfileMigrator') == 1:
+ flags.add('NS_XRE_ENABLE_PROFILE_MIGRATOR')
+ except: pass
+ try:
+ if config.getint('Crash Reporter', 'Enabled') == 1:
+ flags.add('NS_XRE_ENABLE_CRASH_REPORTER')
+ except: pass
+ appdata = dict(("%s:%s" % (s, o), config.get(s, o)) for s in config.sections() for o in config.options(s))
+ appdata['flags'] = ' | '.join(flags) if flags else '0'
+ appdata['App:profile'] = '"%s"' % appdata['App:profile'] if 'App:profile' in appdata else 'NULL'
+ expected = ('App:vendor', 'App:name', 'App:remotingname', 'App:version', 'App:buildid',
+ 'App:id', 'Gecko:minversion', 'Gecko:maxversion')
+ missing = [var for var in expected if var not in appdata]
+ if missing:
+ print >>sys.stderr, \
+ "Missing values in %s: %s" % (file, ', '.join(missing))
+ sys.exit(1)
+
+ if not 'Crash Reporter:serverurl' in appdata:
+ appdata['Crash Reporter:serverurl'] = ''
+
+ print '''#include "nsXREAppData.h"
+ static const nsXREAppData sAppData = {
+ sizeof(nsXREAppData),
+ NULL, // directory
+ "%(App:vendor)s",
+ "%(App:name)s",
+ "%(App:remotingname)s",
+ "%(App:version)s",
+ "%(App:buildid)s",
+ "%(App:id)s",
+ NULL, // copyright
+ %(flags)s,
+ NULL, // xreDirectory
+ "%(Gecko:minversion)s",
+ "%(Gecko:maxversion)s",
+ "%(Crash Reporter:serverurl)s",
+ %(App:profile)s
+ };''' % appdata
+
+if __name__ == '__main__':
+ if len(sys.argv) != 1:
+ main(sys.argv[1])
+ else:
+ print >>sys.stderr, "Usage: %s /path/to/application.ini" % sys.argv[0]
diff --git a/src/third_party/mozjs-45/build/application.ini b/src/third_party/mozjs-45/build/application.ini
new file mode 100644
index 0000000..74b0139
--- /dev/null
+++ b/src/third_party/mozjs-45/build/application.ini
@@ -0,0 +1,51 @@
+#if MOZ_APP_STATIC_INI
+#ifdef MOZ_BUILD_APP_IS_BROWSER
+; This file is not used. If you modify it and want the application to use
+; your modifications, move it under the browser/ subdirectory and start with
+; the "-app /path/to/browser/application.ini" argument.
+#else
+; This file is not used. If you modify it and want the application to use
+; your modifications, start with the "-app /path/to/application.ini"
+; argument.
+#endif
+#endif
+#if 0
+; This Source Code Form is subject to the terms of the Mozilla Public
+; License, v. 2.0. If a copy of the MPL was not distributed with this
+; file, You can obtain one at http://mozilla.org/MPL/2.0/.
+#endif
+#filter substitution
+[App]
+Vendor=@MOZ_APP_VENDOR@
+Name=@MOZ_APP_BASENAME@
+RemotingName=@MOZ_APP_REMOTINGNAME@
+#ifdef MOZ_APP_DISPLAYNAME
+CodeName=@MOZ_APP_DISPLAYNAME@
+#endif
+Version=@MOZ_APP_VERSION@
+#ifdef MOZ_APP_PROFILE
+Profile=@MOZ_APP_PROFILE@
+#endif
+BuildID=@MOZ_APP_BUILDID@
+#ifdef MOZ_SOURCE_REPO
+SourceRepository=@MOZ_SOURCE_REPO@
+#endif
+#ifdef MOZ_SOURCE_STAMP
+SourceStamp=@MOZ_SOURCE_STAMP@
+#endif
+ID=@MOZ_APP_ID@
+
+[Gecko]
+MinVersion=@GRE_MILESTONE@
+MaxVersion=@GRE_MILESTONE@
+
+[XRE]
+#ifdef MOZ_PROFILE_MIGRATOR
+EnableProfileMigrator=1
+#endif
+
+#if MOZ_CRASHREPORTER
+[Crash Reporter]
+Enabled=1
+ServerURL=https://crash-reports.mozilla.com/submit?id=@MOZ_APP_ID@&version=@MOZ_APP_VERSION@&buildid=@MOZ_APP_BUILDID@
+#endif
diff --git a/src/third_party/mozjs-45/build/autoconf/acwinpaths.m4 b/src/third_party/mozjs-45/build/autoconf/acwinpaths.m4
new file mode 100644
index 0000000..ad9c754
--- /dev/null
+++ b/src/third_party/mozjs-45/build/autoconf/acwinpaths.m4
@@ -0,0 +1,31 @@
+dnl This Source Code Form is subject to the terms of the Mozilla Public
+dnl License, v. 2.0. If a copy of the MPL was not distributed with this
+dnl file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+define(GENERATE_SUB_ABS, [
+define([AC_OUTPUT_FILES_SUB1], [
+patsubst($@, [/\*)], [/* | ?:/*)])
+])
+])
+GENERATE_SUB_ABS(defn([AC_OUTPUT_FILES]))
+
+define(GENERATE_SUB_NOSPLIT, [
+define([AC_OUTPUT_FILES], [
+patsubst($@, [-e "s%:% \$ac_given_srcdir/%g"], [])
+])
+])
+GENERATE_SUB_NOSPLIT(defn([AC_OUTPUT_FILES_SUB1]))
+
+define(GENERATE_HEADER_NOSPLIT, [
+define([AC_OUTPUT_HEADER], [
+patsubst($@, [-e "s%:% \$ac_given_srcdir/%g"], [])
+])
+])
+GENERATE_HEADER_NOSPLIT(defn([AC_OUTPUT_HEADER]))
+
+define(GENERATE_SUBDIRS_ABS, [
+define([AC_OUTPUT_SUBDIRS], [
+patsubst($@, [/\*)], [/* | ?:/*)])
+])
+])
+GENERATE_SUBDIRS_ABS(defn([AC_OUTPUT_SUBDIRS]))
diff --git a/src/third_party/mozjs-45/build/autoconf/alloc.m4 b/src/third_party/mozjs-45/build/autoconf/alloc.m4
new file mode 100644
index 0000000..8234a60
--- /dev/null
+++ b/src/third_party/mozjs-45/build/autoconf/alloc.m4
@@ -0,0 +1,53 @@
+dnl This Source Code Form is subject to the terms of the Mozilla Public
+dnl License, v. 2.0. If a copy of the MPL was not distributed with this
+dnl file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+dnl Check for the existence of various allocation headers/functions
+AC_DEFUN([MOZ_CHECK_ALLOCATOR],[
+
+MALLOC_HEADERS="malloc.h malloc_np.h malloc/malloc.h sys/malloc.h"
+MALLOC_H=
+
+for file in $MALLOC_HEADERS; do
+ MOZ_CHECK_HEADER($file, [MALLOC_H=$file])
+ if test "$MALLOC_H" != ""; then
+ AC_DEFINE_UNQUOTED(MALLOC_H, <$MALLOC_H>)
+ break
+ fi
+done
+
+MOZ_CHECK_HEADERS(alloca.h)
+
+AC_CHECK_FUNCS(strndup posix_memalign memalign)
+
+AC_CHECK_FUNCS(malloc_usable_size)
+MALLOC_USABLE_SIZE_CONST_PTR=const
+MOZ_CHECK_HEADERS([malloc.h], [
+ AC_MSG_CHECKING([whether malloc_usable_size definition can use const argument])
+ AC_TRY_COMPILE([#include <malloc.h>
+ #include <stddef.h>
+ size_t malloc_usable_size(const void *ptr);],
+ [return malloc_usable_size(0);],
+ AC_MSG_RESULT([yes]),
+ AC_MSG_RESULT([no])
+ MALLOC_USABLE_SIZE_CONST_PTR=)
+])
+AC_DEFINE_UNQUOTED([MALLOC_USABLE_SIZE_CONST_PTR],[$MALLOC_USABLE_SIZE_CONST_PTR])
+
+
+dnl In newer bionic headers, valloc is built but not defined,
+dnl so we check more carefully here.
+AC_MSG_CHECKING([for valloc in malloc.h])
+AC_EGREP_HEADER(valloc, malloc.h,
+ AC_DEFINE(HAVE_VALLOC)
+ AC_MSG_RESULT([yes]),
+ AC_MSG_RESULT([no]))
+
+AC_MSG_CHECKING([for valloc in unistd.h])
+AC_EGREP_HEADER(valloc, unistd.h,
+ AC_DEFINE(HAVE_VALLOC)
+ AC_MSG_RESULT([yes]),
+ AC_MSG_RESULT([no]))
+
+
+])
diff --git a/src/third_party/mozjs-45/build/autoconf/altoptions.m4 b/src/third_party/mozjs-45/build/autoconf/altoptions.m4
new file mode 100644
index 0000000..f8c8ba9
--- /dev/null
+++ b/src/third_party/mozjs-45/build/autoconf/altoptions.m4
@@ -0,0 +1,123 @@
+dnl This Source Code Form is subject to the terms of the Mozilla Public
+dnl License, v. 2.0. If a copy of the MPL was not distributed with this
+dnl file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+dnl altoptions.m4 - An alternative way of specifying command-line options.
+dnl These macros are needed to support a menu-based configurator.
+dnl This file also includes the macro, AM_READ_MYCONFIG, for reading
+dnl the 'myconfig.m4' file.
+
+dnl Send comments, improvements, bugs to Steve Lamm (slamm@netscape.com).
+
+
+dnl MOZ_ARG_ENABLE_BOOL( NAME, HELP, IF-YES [, IF-NO [, ELSE]])
+dnl MOZ_ARG_DISABLE_BOOL( NAME, HELP, IF-NO [, IF-YES [, ELSE]])
+dnl MOZ_ARG_ENABLE_STRING( NAME, HELP, IF-SET [, ELSE])
+dnl MOZ_ARG_ENABLE_BOOL_OR_STRING( NAME, HELP, IF-YES, IF-NO, IF-SET[, ELSE]]])
+dnl MOZ_ARG_WITH_BOOL( NAME, HELP, IF-YES [, IF-NO [, ELSE])
+dnl MOZ_ARG_WITHOUT_BOOL( NAME, HELP, IF-NO [, IF-YES [, ELSE])
+dnl MOZ_ARG_WITH_STRING( NAME, HELP, IF-SET [, ELSE])
+dnl MOZ_ARG_HEADER(Comment)
+dnl MOZ_READ_MYCONFIG() - Read in 'myconfig.sh' file
+
+
+dnl MOZ_TWO_STRING_TEST(NAME, VAL, STR1, IF-STR1, STR2, IF-STR2 [, ELSE])
+AC_DEFUN([MOZ_TWO_STRING_TEST],
+[if test "[$2]" = "[$3]"; then
+ ifelse([$4], , :, [$4])
+ elif test "[$2]" = "[$5]"; then
+ ifelse([$6], , :, [$6])
+ else
+ ifelse([$7], ,
+ [AC_MSG_ERROR([Option, [$1], does not take an argument ([$2]).])],
+ [$7])
+ fi])
+
+dnl MOZ_ARG_ENABLE_BOOL(NAME, HELP, IF-YES [, IF-NO [, ELSE]])
+AC_DEFUN([MOZ_ARG_ENABLE_BOOL],
+[AC_ARG_ENABLE([$1], [$2],
+ [MOZ_TWO_STRING_TEST([$1], [$enableval], yes, [$3], no, [$4])],
+ [$5])])
+
+dnl MOZ_ARG_DISABLE_BOOL(NAME, HELP, IF-NO [, IF-YES [, ELSE]])
+AC_DEFUN([MOZ_ARG_DISABLE_BOOL],
+[AC_ARG_ENABLE([$1], [$2],
+ [MOZ_TWO_STRING_TEST([$1], [$enableval], no, [$3], yes, [$4])],
+ [$5])])
+
+dnl MOZ_ARG_ENABLE_STRING(NAME, HELP, IF-SET [, ELSE])
+AC_DEFUN([MOZ_ARG_ENABLE_STRING],
+[AC_ARG_ENABLE([$1], [$2], [$3], [$4])])
+
+dnl MOZ_ARG_ENABLE_BOOL_OR_STRING(NAME, HELP, IF-YES, IF-NO, IF-SET[, ELSE]]])
+AC_DEFUN([MOZ_ARG_ENABLE_BOOL_OR_STRING],
+[ifelse([$5], ,
+ [errprint([Option, $1, needs an "IF-SET" argument.
+])
+ m4exit(1)],
+ [AC_ARG_ENABLE([$1], [$2],
+ [MOZ_TWO_STRING_TEST([$1], [$enableval], yes, [$3], no, [$4], [$5])],
+ [$6])])])
+
+dnl MOZ_ARG_WITH_BOOL(NAME, HELP, IF-YES [, IF-NO [, ELSE])
+AC_DEFUN([MOZ_ARG_WITH_BOOL],
+[AC_ARG_WITH([$1], [$2],
+ [MOZ_TWO_STRING_TEST([$1], [$withval], yes, [$3], no, [$4])],
+ [$5])])
+
+dnl MOZ_ARG_WITHOUT_BOOL(NAME, HELP, IF-NO [, IF-YES [, ELSE])
+AC_DEFUN([MOZ_ARG_WITHOUT_BOOL],
+[AC_ARG_WITH([$1], [$2],
+ [MOZ_TWO_STRING_TEST([$1], [$withval], no, [$3], yes, [$4])],
+ [$5])])
+
+dnl MOZ_ARG_WITH_STRING(NAME, HELP, IF-SET [, ELSE])
+AC_DEFUN([MOZ_ARG_WITH_STRING],
+[AC_ARG_WITH([$1], [$2], [$3], [$4])])
+
+dnl MOZ_ARG_HEADER(Comment)
+dnl This is used by webconfig to group options
+define(MOZ_ARG_HEADER, [# $1])
+
+dnl MOZ_READ_MYCONFIG() - Read in 'myconfig.sh' file
+AC_DEFUN([MOZ_READ_MOZCONFIG],
+[AC_REQUIRE([AC_INIT_BINSH])dnl
+inserted=
+dnl Shell is hard, so here is what the following does:
+dnl - Reset $@ (command line arguments)
+dnl - Add the configure options from mozconfig to $@ one by one
+dnl - Add the original command line arguments after that, one by one
+dnl
+dnl There are several tricks involved:
+dnl - It is not possible to preserve the whitespaces in $@ by assigning to
+dnl another variable, so the two first steps above need to happen in the first
+dnl iteration of the third step.
+dnl - We always want the configure options to be added, so the loop must be
+dnl iterated at least once, so we add a dummy argument first, and discard it.
+dnl - something | while read line ... makes the while run in a subshell, meaning
+dnl that anything it does is not propagated to the main shell, so we can't do
+dnl set -- foo there. As a consequence, what the while loop reading mach
+dnl environment output does is output a set of shell commands for the main shell
+dnl to eval.
+dnl - Extra care is due when lines from mach environment output contain special
+dnl shell characters, so we use ' for quoting and ensure no ' end up in between
+dnl the quoting mark unescaped.
+dnl Some of the above is directly done in mach environment --format=configure.
+failed_eval() {
+ echo "Failed eval'ing the following:"
+ $(dirname [$]0)/[$1]/mach environment --format=configure
+ exit 1
+}
+
+set -- dummy "[$]@"
+for ac_option
+do
+ if test -z "$inserted"; then
+ set --
+ eval "$($(dirname [$]0)/[$1]/mach environment --format=configure)" || failed_eval
+ inserted=1
+ else
+ set -- "[$]@" "$ac_option"
+ fi
+done
+])
diff --git a/src/third_party/mozjs-45/build/autoconf/android.m4 b/src/third_party/mozjs-45/build/autoconf/android.m4
new file mode 100644
index 0000000..f5d7430
--- /dev/null
+++ b/src/third_party/mozjs-45/build/autoconf/android.m4
@@ -0,0 +1,512 @@
+dnl This Source Code Form is subject to the terms of the Mozilla Public
+dnl License, v. 2.0. If a copy of the MPL was not distributed with this
+dnl file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+AC_DEFUN([MOZ_ANDROID_NDK],
+[
+
+MOZ_ARG_WITH_STRING(android-ndk,
+[ --with-android-ndk=DIR
+ location where the Android NDK can be found],
+ android_ndk=$withval)
+
+MOZ_ARG_WITH_STRING(android-toolchain,
+[ --with-android-toolchain=DIR
+ location of the Android toolchain],
+ android_toolchain=$withval)
+
+MOZ_ARG_WITH_STRING(android-gnu-compiler-version,
+[ --with-android-gnu-compiler-version=VER
+ gnu compiler version to use],
+ android_gnu_compiler_version=$withval)
+
+MOZ_ARG_WITH_STRING(android-cxx-stl,
+[ --with-android-cxx-stl=VALUE
+ use the specified C++ STL (stlport, libstdc++, libc++)],
+ android_cxx_stl=$withval,
+ android_cxx_stl=mozstlport)
+
+define([MIN_ANDROID_VERSION], [9])
+android_version=MIN_ANDROID_VERSION
+
+MOZ_ARG_WITH_STRING(android-version,
+[ --with-android-version=VER
+ android platform version, default] MIN_ANDROID_VERSION,
+ android_version=$withval)
+
+if test $android_version -lt MIN_ANDROID_VERSION ; then
+ AC_MSG_ERROR([--with-android-version must be at least MIN_ANDROID_VERSION.])
+fi
+
+case "$target" in
+arm-*linux*-android*|*-linuxandroid*)
+ android_tool_prefix="arm-linux-androideabi"
+ ;;
+i?86-*android*)
+ android_tool_prefix="i686-linux-android"
+ ;;
+mipsel-*android*)
+ android_tool_prefix="mipsel-linux-android"
+ ;;
+*)
+ android_tool_prefix="$target_os"
+ ;;
+esac
+
+case "$target" in
+*-android*|*-linuxandroid*)
+ if test -z "$android_ndk" ; then
+ AC_MSG_ERROR([You must specify --with-android-ndk=/path/to/ndk when targeting Android.])
+ fi
+
+ if test -z "$android_toolchain" ; then
+ AC_MSG_CHECKING([for android toolchain directory])
+
+ kernel_name=`uname -s | tr "[[:upper:]]" "[[:lower:]]"`
+
+ for version in $android_gnu_compiler_version 4.9 4.8 4.7; do
+ case "$target_cpu" in
+ arm)
+ target_name=arm-linux-androideabi-$version
+ ;;
+ i?86)
+ target_name=x86-$version
+ ;;
+ mipsel)
+ target_name=mipsel-linux-android-$version
+ ;;
+ *)
+ AC_MSG_ERROR([target cpu is not supported])
+ ;;
+ esac
+ case "$host_cpu" in
+ i*86)
+ android_toolchain="$android_ndk"/toolchains/$target_name/prebuilt/$kernel_name-x86
+ ;;
+ x86_64)
+ android_toolchain="$android_ndk"/toolchains/$target_name/prebuilt/$kernel_name-x86_64
+ if ! test -d "$android_toolchain" ; then
+ android_toolchain="$android_ndk"/toolchains/$target_name/prebuilt/$kernel_name-x86
+ fi
+ ;;
+ *)
+ AC_MSG_ERROR([No known toolchain for your host cpu])
+ ;;
+ esac
+ if test -d "$android_toolchain" ; then
+ android_gnu_compiler_version=$version
+ break
+ elif test -n "$android_gnu_compiler_version" ; then
+ AC_MSG_ERROR([not found. Your --with-android-gnu-compiler-version may be wrong.])
+ fi
+ done
+
+ if test -z "$android_gnu_compiler_version" ; then
+ AC_MSG_ERROR([not found. You have to specify --with-android-toolchain=/path/to/ndk/toolchain.])
+ else
+ AC_MSG_RESULT([$android_toolchain])
+ fi
+ NSPR_CONFIGURE_ARGS="$NSPR_CONFIGURE_ARGS --with-android-toolchain=$android_toolchain"
+ fi
+
+ NSPR_CONFIGURE_ARGS="$NSPR_CONFIGURE_ARGS --with-android-version=$android_version"
+
+ AC_MSG_CHECKING([for android platform directory])
+
+ case "$target_cpu" in
+ arm)
+ target_name=arm
+ ;;
+ i?86)
+ target_name=x86
+ ;;
+ mipsel)
+ target_name=mips
+ ;;
+ esac
+
+ android_platform="$android_ndk"/platforms/android-"$android_version"/arch-"$target_name"
+
+ if test -d "$android_platform" ; then
+ AC_MSG_RESULT([$android_platform])
+ else
+ AC_MSG_ERROR([not found. Please check your NDK. With the current configuration, it should be in $android_platform])
+ fi
+
+ dnl set up compilers
+ TOOLCHAIN_PREFIX="$android_toolchain/bin/$android_tool_prefix-"
+ AS="$android_toolchain"/bin/"$android_tool_prefix"-as
+ if test -z "$CC"; then
+ CC="$android_toolchain"/bin/"$android_tool_prefix"-gcc
+ fi
+ if test -z "$CXX"; then
+ CXX="$android_toolchain"/bin/"$android_tool_prefix"-g++
+ fi
+ if test -z "$CPP"; then
+ CPP="$android_toolchain"/bin/"$android_tool_prefix"-cpp
+ fi
+ LD="$android_toolchain"/bin/"$android_tool_prefix"-ld
+ AR="$android_toolchain"/bin/"$android_tool_prefix"-ar
+ RANLIB="$android_toolchain"/bin/"$android_tool_prefix"-ranlib
+ STRIP="$android_toolchain"/bin/"$android_tool_prefix"-strip
+ OBJCOPY="$android_toolchain"/bin/"$android_tool_prefix"-objcopy
+
+ CPPFLAGS="-idirafter $android_platform/usr/include $CPPFLAGS"
+ CFLAGS="-mandroid -fno-short-enums -fno-exceptions $CFLAGS"
+ CXXFLAGS="-mandroid -fno-short-enums -fno-exceptions -Wno-psabi $CXXFLAGS"
+ ASFLAGS="-idirafter $android_platform/usr/include -DANDROID $ASFLAGS"
+
+ dnl Add -llog by default, since we use it all over the place.
+ dnl Add --allow-shlib-undefined, because libGLESv2 links to an
+ dnl undefined symbol (present on the hardware, just not in the
+ dnl NDK.)
+ LDFLAGS="-mandroid -L$android_platform/usr/lib -Wl,-rpath-link=$android_platform/usr/lib --sysroot=$android_platform -llog -Wl,--allow-shlib-undefined $LDFLAGS"
+ dnl prevent cross compile section from using these flags as host flags
+ if test -z "$HOST_CPPFLAGS" ; then
+ HOST_CPPFLAGS=" "
+ fi
+ if test -z "$HOST_CFLAGS" ; then
+ HOST_CFLAGS=" "
+ fi
+ if test -z "$HOST_CXXFLAGS" ; then
+ HOST_CXXFLAGS=" "
+ fi
+ if test -z "$HOST_LDFLAGS" ; then
+ HOST_LDFLAGS=" "
+ fi
+
+ ANDROID_NDK="${android_ndk}"
+ ANDROID_TOOLCHAIN="${android_toolchain}"
+ ANDROID_PLATFORM="${android_platform}"
+
+ AC_DEFINE(ANDROID)
+ AC_SUBST(ANDROID_NDK)
+ AC_SUBST(ANDROID_TOOLCHAIN)
+ AC_SUBST(ANDROID_PLATFORM)
+
+ ;;
+esac
+
+])
+
+AC_DEFUN([MOZ_ANDROID_CPU_ARCH],
+[
+
+if test "$OS_TARGET" = "Android" -a -z "$gonkdir"; then
+ case "${CPU_ARCH}-${MOZ_ARCH}" in
+ arm-armv7*)
+ ANDROID_CPU_ARCH=armeabi-v7a
+ ;;
+ arm-*)
+ ANDROID_CPU_ARCH=armeabi
+ ;;
+ x86-*)
+ ANDROID_CPU_ARCH=x86
+ ;;
+ mips-*) # When target_cpu is mipsel, CPU_ARCH is mips
+ ANDROID_CPU_ARCH=mips
+ ;;
+ esac
+
+ AC_SUBST(ANDROID_CPU_ARCH)
+fi
+])
+
+AC_DEFUN([MOZ_ANDROID_STLPORT],
+[
+
+if test "$OS_TARGET" = "Android" -a -z "$gonkdir"; then
+ cpu_arch_dir="$ANDROID_CPU_ARCH"
+ if test "$MOZ_THUMB2" = 1; then
+ cpu_arch_dir="$cpu_arch_dir/thumb"
+ fi
+
+ if test -z "$STLPORT_CPPFLAGS$STLPORT_LIBS"; then
+ case "$android_cxx_stl" in
+ libstdc++)
+ # android-ndk-r8b and later
+ ndk_base="$android_ndk/sources/cxx-stl/gnu-libstdc++/$android_gnu_compiler_version"
+ ndk_libs_include="$ndk_base/libs/$ANDROID_CPU_ARCH"
+ ndk_libs="$ndk_base/libs/$cpu_arch_dir"
+ ndk_include="$ndk_base/include"
+
+ if ! test -e "$ndk_libs/libgnustl_static.a"; then
+ AC_MSG_ERROR([Couldn't find path to gnu-libstdc++ in the android ndk])
+ fi
+
+ STLPORT_LIBS="-L$ndk_libs -lgnustl_static"
+ STLPORT_CPPFLAGS="-I$ndk_include -I$ndk_include/backward -I$ndk_libs_include/include"
+ ;;
+ libc++)
+ # android-ndk-r8b and later
+ ndk_base="$android_ndk/sources/cxx-stl"
+ cxx_base="$ndk_base/llvm-libc++"
+ cxx_libs="$cxx_base/libs/$cpu_arch_dir"
+ cxx_include="$cxx_base/libcxx/include"
+ cxxabi_base="$ndk_base/llvm-libc++abi"
+ cxxabi_include="$cxxabi_base/libcxxabi/include"
+
+ if ! test -e "$cxx_libs/libc++_static.a"; then
+ AC_MSG_ERROR([Couldn't find path to llvm-libc++ in the android ndk])
+ fi
+
+ STLPORT_LIBS="-L$cxx_libs -lc++_static"
+ # Add android/support/include/ for prototyping long double math
+ # functions, locale-specific C library functions, multibyte support,
+ # etc.
+ STLPORT_CPPFLAGS="-I$android_ndk/sources/android/support/include -I$cxx_include -I$cxxabi_include"
+ ;;
+ mozstlport)
+ # We don't need to set STLPORT_LIBS, because the build system will
+ # take care of linking in our home-built stlport where it is needed.
+ STLPORT_CPPFLAGS="-isystem $_topsrcdir/build/stlport/stlport -isystem $_topsrcdir/build/stlport/overrides -isystem $android_ndk/sources/cxx-stl/system/include"
+ ;;
+ *)
+ AC_MSG_ERROR([Bad value for --enable-android-cxx-stl])
+ ;;
+ esac
+ fi
+ CXXFLAGS="$CXXFLAGS $STLPORT_CPPFLAGS"
+fi
+MOZ_ANDROID_CXX_STL=$android_cxx_stl
+AC_SUBST([MOZ_ANDROID_CXX_STL])
+AC_SUBST([STLPORT_LIBS])
+
+])
+
+
+AC_DEFUN([concat],[$1$2$3$4])
+
+dnl Find a component of an AAR.
+dnl Arg 1: variable name to expose, like ANDROID_SUPPORT_V4_LIB.
+dnl Arg 2: path to component.
+dnl Arg 3: if non-empty, expect and require component.
+AC_DEFUN([MOZ_ANDROID_AAR_COMPONENT], [
+ ifelse([$3], ,
+ [
+ if test -e "$$1" ; then
+ AC_MSG_ERROR([Found unexpected exploded $1!])
+ fi
+ ],
+ [
+ AC_MSG_CHECKING([for $1])
+ $1="$2"
+ if ! test -e "$$1" ; then
+ AC_MSG_ERROR([Could not find required exploded $1!])
+ fi
+ AC_MSG_RESULT([$$1])
+ AC_SUBST($1)
+ ])
+])
+
+dnl Find an AAR and expose variables representing its exploded components.
+dnl AC_SUBSTs ANDROID_NAME_{AAR,AAR_RES,AAR_LIB,AAR_INTERNAL_LIB}.
+dnl Arg 1: name, like play-services-base
+dnl Arg 2: version, like 7.8.0
+dnl Arg 3: extras subdirectory, either android or google
+dnl Arg 4: package subdirectory, like com/google/android/gms
+dnl Arg 5: if non-empty, expect and require internal_impl JAR.
+dnl Arg 6: if non-empty, expect and require assets/ directory.
+AC_DEFUN([MOZ_ANDROID_AAR],[
+ define([local_aar_var_base], translit($1, [-a-z], [_A-Z]))
+ define([local_aar_var], concat(ANDROID_, local_aar_var_base, _AAR))
+ local_aar_var="$ANDROID_SDK_ROOT/extras/$3/m2repository/$4/$1/$2/$1-$2.aar"
+ AC_MSG_CHECKING([for $1 AAR])
+ if ! test -e "$local_aar_var" ; then
+ AC_MSG_ERROR([You must download the $1 AAR. Run the Android SDK tool and install the Android and Google Support Repositories under Extras. See https://developer.android.com/tools/extras/support-library.html for more info. (Looked for $local_aar_var)])
+ fi
+ AC_SUBST(local_aar_var)
+ AC_MSG_RESULT([$local_aar_var])
+
+ if ! $PYTHON -m mozbuild.action.explode_aar --destdir=$MOZ_BUILD_ROOT/dist/exploded-aar $local_aar_var ; then
+ AC_MSG_ERROR([Could not explode $local_aar_var!])
+ fi
+
+ define([root], $MOZ_BUILD_ROOT/dist/exploded-aar/$1-$2/)
+ MOZ_ANDROID_AAR_COMPONENT(concat(local_aar_var, _LIB), concat(root, $1-$2-classes.jar), REQUIRED)
+ MOZ_ANDROID_AAR_COMPONENT(concat(local_aar_var, _RES), concat(root, res), REQUIRED)
+ MOZ_ANDROID_AAR_COMPONENT(concat(local_aar_var, _INTERNAL_LIB), concat(root, libs/$1-$2-internal_impl-$2.jar), $5)
+ MOZ_ANDROID_AAR_COMPONENT(concat(local_aar_var, _ASSETS), concat(root, assets), $6)
+])
+
+AC_DEFUN([MOZ_ANDROID_GOOGLE_PLAY_SERVICES],
+[
+
+if test -n "$MOZ_NATIVE_DEVICES" ; then
+ AC_SUBST(MOZ_NATIVE_DEVICES)
+
+ MOZ_ANDROID_AAR(play-services-base, 8.1.0, google, com/google/android/gms)
+ MOZ_ANDROID_AAR(play-services-basement, 8.1.0, google, com/google/android/gms)
+ MOZ_ANDROID_AAR(play-services-cast, 8.1.0, google, com/google/android/gms)
+ MOZ_ANDROID_AAR(mediarouter-v7, 23.0.1, android, com/android/support, REQUIRED_INTERNAL_IMPL)
+fi
+
+])
+
+AC_DEFUN([MOZ_ANDROID_GOOGLE_CLOUD_MESSAGING],
+[
+
+if test -n "$MOZ_ANDROID_GCM" ; then
+ AC_SUBST(MOZ_ANDROID_GCM)
+
+ MOZ_ANDROID_AAR(play-services-base, 8.1.0, google, com/google/android/gms)
+ MOZ_ANDROID_AAR(play-services-basement, 8.1.0, google, com/google/android/gms)
+ MOZ_ANDROID_AAR(play-services-gcm, 8.1.0, google, com/google/android/gms)
+fi
+
+])
+
+AC_DEFUN([MOZ_ANDROID_INSTALL_TRACKING],
+[
+
+if test -n "$MOZ_INSTALL_TRACKING"; then
+ AC_SUBST(MOZ_INSTALL_TRACKING)
+ MOZ_ANDROID_AAR(play-services-ads, 8.1.0, google, com/google/android/gms)
+ MOZ_ANDROID_AAR(play-services-analytics, 8.1.0, google, com/google/android/gms)
+ MOZ_ANDROID_AAR(play-services-appindexing, 8.1.0, google, com/google/android/gms)
+ MOZ_ANDROID_AAR(play-services-basement, 8.1.0, google, com/google/android/gms)
+fi
+
+])
+
+dnl Configure an Android SDK.
+dnl Arg 1: target SDK version, like 22.
+dnl Arg 2: build tools version, like 22.0.1.
+AC_DEFUN([MOZ_ANDROID_SDK],
+[
+
+MOZ_ARG_WITH_STRING(android-sdk,
+[ --with-android-sdk=DIR
+ location where the Android SDK can be found (like ~/.mozbuild/android-sdk-linux)],
+ android_sdk_root=$withval)
+
+android_sdk_root=${withval%/platforms/android-*}
+
+case "$target" in
+*-android*|*-linuxandroid*)
+ if test -z "$android_sdk_root" ; then
+ AC_MSG_ERROR([You must specify --with-android-sdk=/path/to/sdk when targeting Android.])
+ fi
+
+ # We were given an old-style
+ # --with-android-sdk=/path/to/sdk/platforms/android-*. We could warn, but
+ # we'll get compliance by forcing the issue.
+ if test -e "$withval"/source.properties ; then
+ AC_MSG_ERROR([Including platforms/android-* in --with-android-sdk arguments is deprecated. Use --with-android-sdk=$android_sdk_root.])
+ fi
+
+ android_target_sdk=$1
+ AC_MSG_CHECKING([for Android SDK platform version $android_target_sdk])
+ android_sdk=$android_sdk_root/platforms/android-$android_target_sdk
+ if ! test -e "$android_sdk/source.properties" ; then
+ AC_MSG_ERROR([You must download Android SDK platform version $android_target_sdk. Try |mach bootstrap|. (Looked for $android_sdk)])
+ fi
+ AC_MSG_RESULT([$android_sdk])
+
+ android_build_tools="$android_sdk_root"/build-tools/$2
+ AC_MSG_CHECKING([for Android build-tools version $2])
+ if test -d "$android_build_tools" -a -f "$android_build_tools/aapt"; then
+ AC_MSG_RESULT([$android_build_tools])
+ else
+ AC_MSG_ERROR([You must install the Android build-tools version $2. Try |mach bootstrap|. (Looked for $android_build_tools)])
+ fi
+
+ MOZ_PATH_PROG(ZIPALIGN, zipalign, :, [$android_build_tools])
+ MOZ_PATH_PROG(DX, dx, :, [$android_build_tools])
+ MOZ_PATH_PROG(AAPT, aapt, :, [$android_build_tools])
+ MOZ_PATH_PROG(AIDL, aidl, :, [$android_build_tools])
+ if test -z "$ZIPALIGN" -o "$ZIPALIGN" = ":"; then
+ AC_MSG_ERROR([The program zipalign was not found. Try |mach bootstrap|.])
+ fi
+ if test -z "$DX" -o "$DX" = ":"; then
+ AC_MSG_ERROR([The program dx was not found. Try |mach bootstrap|.])
+ fi
+ if test -z "$AAPT" -o "$AAPT" = ":"; then
+ AC_MSG_ERROR([The program aapt was not found. Try |mach bootstrap|.])
+ fi
+ if test -z "$AIDL" -o "$AIDL" = ":"; then
+ AC_MSG_ERROR([The program aidl was not found. Try |mach bootstrap|.])
+ fi
+
+ android_platform_tools="$android_sdk_root"/platform-tools
+ AC_MSG_CHECKING([for Android platform-tools])
+ if test -d "$android_platform_tools" -a -f "$android_platform_tools/adb"; then
+ AC_MSG_RESULT([$android_platform_tools])
+ else
+ AC_MSG_ERROR([You must install the Android platform-tools. Try |mach bootstrap|. (Looked for $android_platform_tools)])
+ fi
+
+ MOZ_PATH_PROG(ADB, adb, :, [$android_platform_tools])
+ if test -z "$ADB" -o "$ADB" = ":"; then
+ AC_MSG_ERROR([The program adb was not found. Try |mach bootstrap|.])
+ fi
+
+ android_tools="$android_sdk_root"/tools
+ AC_MSG_CHECKING([for Android tools])
+ if test -d "$android_tools" -a -f "$android_tools/emulator"; then
+ AC_MSG_RESULT([$android_tools])
+ else
+ AC_MSG_ERROR([You must install the Android tools. Try |mach bootstrap|. (Looked for $android_tools)])
+ fi
+
+ MOZ_PATH_PROG(EMULATOR, emulator, :, [$android_tools])
+ if test -z "$EMULATOR" -o "$EMULATOR" = ":"; then
+ AC_MSG_ERROR([The program emulator was not found. Try |mach bootstrap|.])
+ fi
+
+ ANDROID_TARGET_SDK="${android_target_sdk}"
+ ANDROID_SDK="${android_sdk}"
+ ANDROID_SDK_ROOT="${android_sdk_root}"
+ ANDROID_TOOLS="${android_tools}"
+ AC_DEFINE_UNQUOTED(ANDROID_TARGET_SDK,$ANDROID_TARGET_SDK)
+ AC_SUBST(ANDROID_TARGET_SDK)
+ AC_SUBST(ANDROID_SDK_ROOT)
+ AC_SUBST(ANDROID_SDK)
+ AC_SUBST(ANDROID_TOOLS)
+
+ MOZ_ANDROID_AAR(appcompat-v7, 23.0.1, android, com/android/support)
+ MOZ_ANDROID_AAR(design, 23.0.1, android, com/android/support)
+ MOZ_ANDROID_AAR(recyclerview-v7, 23.0.1, android, com/android/support)
+ MOZ_ANDROID_AAR(support-v4, 23.0.1, android, com/android/support, REQUIRED_INTERNAL_IMPL)
+
+ ANDROID_SUPPORT_ANNOTATIONS_JAR="$ANDROID_SDK_ROOT/extras/android/m2repository/com/android/support/support-annotations/23.0.1/support-annotations-23.0.1.jar"
+ AC_MSG_CHECKING([for support-annotations JAR])
+ if ! test -e $ANDROID_SUPPORT_ANNOTATIONS_JAR ; then
+ AC_MSG_ERROR([You must download the support-annotations lib. Run the Android SDK tool and install the Android Support Repository under Extras. See https://developer.android.com/tools/extras/support-library.html for more info. (looked for $ANDROID_SUPPORT_ANNOTATIONS_JAR)])
+ fi
+ AC_MSG_RESULT([$ANDROID_SUPPORT_ANNOTATIONS_JAR])
+ AC_SUBST(ANDROID_SUPPORT_ANNOTATIONS_JAR)
+ ANDROID_SUPPORT_ANNOTATIONS_JAR_LIB=$ANDROID_SUPPORT_ANNOTATIONS_JAR
+ AC_SUBST(ANDROID_SUPPORT_ANNOTATIONS_JAR_LIB)
+ ;;
+esac
+
+MOZ_ARG_WITH_STRING(android-min-sdk,
+[ --with-android-min-sdk=[VER] Impose a minimum Firefox for Android SDK version],
+[ MOZ_ANDROID_MIN_SDK_VERSION=$withval ])
+
+MOZ_ARG_WITH_STRING(android-max-sdk,
+[ --with-android-max-sdk=[VER] Impose a maximum Firefox for Android SDK version],
+[ MOZ_ANDROID_MAX_SDK_VERSION=$withval ])
+
+if test -n "$MOZ_ANDROID_MIN_SDK_VERSION"; then
+ if test -n "$MOZ_ANDROID_MAX_SDK_VERSION"; then
+ if test $MOZ_ANDROID_MAX_SDK_VERSION -lt $MOZ_ANDROID_MIN_SDK_VERSION ; then
+ AC_MSG_ERROR([--with-android-max-sdk must be at least the value of --with-android-min-sdk.])
+ fi
+ fi
+
+ if test $MOZ_ANDROID_MIN_SDK_VERSION -gt $ANDROID_TARGET_SDK ; then
+ AC_MSG_ERROR([--with-android-min-sdk is expected to be less than $ANDROID_TARGET_SDK])
+ fi
+
+ AC_DEFINE_UNQUOTED(MOZ_ANDROID_MIN_SDK_VERSION, $MOZ_ANDROID_MIN_SDK_VERSION)
+ AC_SUBST(MOZ_ANDROID_MIN_SDK_VERSION)
+fi
+
+if test -n "$MOZ_ANDROID_MAX_SDK_VERSION"; then
+ AC_DEFINE_UNQUOTED(MOZ_ANDROID_MAX_SDK_VERSION, $MOZ_ANDROID_MAX_SDK_VERSION)
+ AC_SUBST(MOZ_ANDROID_MAX_SDK_VERSION)
+fi
+
+])
diff --git a/src/third_party/mozjs-45/build/autoconf/arch.m4 b/src/third_party/mozjs-45/build/autoconf/arch.m4
new file mode 100644
index 0000000..b62ea71
--- /dev/null
+++ b/src/third_party/mozjs-45/build/autoconf/arch.m4
@@ -0,0 +1,260 @@
+dnl This Source Code Form is subject to the terms of the Mozilla Public
+dnl License, v. 2.0. If a copy of the MPL was not distributed with this
+dnl file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+AC_DEFUN([MOZ_ARCH_OPTS],
+[
+
+dnl ========================================================
+dnl = ARM toolchain tweaks
+dnl ========================================================
+
+MOZ_THUMB=toolchain-default
+MOZ_THUMB_INTERWORK=toolchain-default
+MOZ_FPU=toolchain-default
+MOZ_FLOAT_ABI=toolchain-default
+MOZ_SOFT_FLOAT=toolchain-default
+MOZ_ALIGN=toolchain-default
+
+MOZ_ARG_WITH_STRING(arch,
+[ --with-arch=[[type|toolchain-default]]
+ Use specific CPU features (-march=type). Resets
+ thumb, fpu, float-abi, etc. defaults when set],
+ if test -z "$GNU_CC"; then
+ AC_MSG_ERROR([--with-arch is not supported on non-GNU toolchains])
+ fi
+ MOZ_ARCH=$withval)
+
+if test -z "$MOZ_ARCH"; then
+ dnl Defaults
+ case "${CPU_ARCH}-${OS_TARGET}" in
+ arm-Android)
+ MOZ_THUMB=yes
+ MOZ_ARCH=armv7-a
+ MOZ_FPU=vfp
+ MOZ_FLOAT_ABI=softfp
+ MOZ_ALIGN=no
+ ;;
+ arm-Darwin)
+ MOZ_ARCH=toolchain-default
+ ;;
+ esac
+fi
+
+if test "$MOZ_ARCH" = "armv6" -a "$OS_TARGET" = "Android"; then
+ MOZ_FPU=vfp
+fi
+
+MOZ_ARG_WITH_STRING(thumb,
+[ --with-thumb[[=yes|no|toolchain-default]]]
+[ Use Thumb instruction set (-mthumb)],
+ if test -z "$GNU_CC"; then
+ AC_MSG_ERROR([--with-thumb is not supported on non-GNU toolchains])
+ fi
+ MOZ_THUMB=$withval)
+
+MOZ_ARG_WITH_STRING(thumb-interwork,
+[ --with-thumb-interwork[[=yes|no|toolchain-default]]
+ Use Thumb/ARM instuctions interwork (-mthumb-interwork)],
+ if test -z "$GNU_CC"; then
+ AC_MSG_ERROR([--with-thumb-interwork is not supported on non-GNU toolchains])
+ fi
+ MOZ_THUMB_INTERWORK=$withval)
+
+MOZ_ARG_WITH_STRING(fpu,
+[ --with-fpu=[[type|toolchain-default]]
+ Use specific FPU type (-mfpu=type)],
+ if test -z "$GNU_CC"; then
+ AC_MSG_ERROR([--with-fpu is not supported on non-GNU toolchains])
+ fi
+ MOZ_FPU=$withval)
+
+MOZ_ARG_WITH_STRING(float-abi,
+[ --with-float-abi=[[type|toolchain-default]]
+ Use specific arm float ABI (-mfloat-abi=type)],
+ if test -z "$GNU_CC"; then
+ AC_MSG_ERROR([--with-float-abi is not supported on non-GNU toolchains])
+ fi
+ MOZ_FLOAT_ABI=$withval)
+
+MOZ_ARG_WITH_STRING(soft-float,
+[ --with-soft-float[[=yes|no|toolchain-default]]
+ Use soft float library (-msoft-float)],
+ if test -z "$GNU_CC"; then
+ AC_MSG_ERROR([--with-soft-float is not supported on non-GNU toolchains])
+ fi
+ MOZ_SOFT_FLOAT=$withval)
+
+case "$MOZ_ARCH" in
+toolchain-default|"")
+ arch_flag=""
+ ;;
+*)
+ arch_flag="-march=$MOZ_ARCH"
+ ;;
+esac
+
+case "$MOZ_THUMB" in
+yes)
+ MOZ_THUMB2=1
+ thumb_flag="-mthumb"
+ ;;
+no)
+ MOZ_THUMB2=
+ thumb_flag="-marm"
+ ;;
+*)
+ _SAVE_CFLAGS="$CFLAGS"
+ CFLAGS="$arch_flag"
+ AC_TRY_COMPILE([],[return sizeof(__thumb2__);],
+ MOZ_THUMB2=1,
+ MOZ_THUMB2=)
+ CFLAGS="$_SAVE_CFLAGS"
+ thumb_flag=""
+ ;;
+esac
+
+if test "$MOZ_THUMB2" = 1; then
+ AC_DEFINE(MOZ_THUMB2)
+fi
+
+case "$MOZ_THUMB_INTERWORK" in
+yes)
+ thumb_interwork_flag="-mthumb-interwork"
+ ;;
+no)
+ thumb_interwork_flag="-mno-thumb-interwork"
+ ;;
+*) # toolchain-default
+ thumb_interwork_flag=""
+ ;;
+esac
+
+case "$MOZ_FPU" in
+toolchain-default|"")
+ fpu_flag=""
+ ;;
+*)
+ fpu_flag="-mfpu=$MOZ_FPU"
+ ;;
+esac
+
+case "$MOZ_FLOAT_ABI" in
+toolchain-default|"")
+ float_abi_flag=""
+ ;;
+*)
+ float_abi_flag="-mfloat-abi=$MOZ_FLOAT_ABI"
+ ;;
+esac
+
+case "$MOZ_SOFT_FLOAT" in
+yes)
+ soft_float_flag="-msoft-float"
+ ;;
+no)
+ soft_float_flag="-mno-soft-float"
+ ;;
+*) # toolchain-default
+ soft_float_flag=""
+ ;;
+esac
+
+case "$MOZ_ALIGN" in
+no)
+ align_flag="-mno-unaligned-access"
+ ;;
+yes)
+ align_flag="-munaligned-access"
+ ;;
+*)
+ align_flag=""
+ ;;
+esac
+
+if test -n "$align_flag"; then
+ _SAVE_CFLAGS="$CFLAGS"
+ CFLAGS="$CFLAGS $align_flag"
+ AC_MSG_CHECKING(whether alignment flag ($align_flag) is supported)
+ AC_TRY_COMPILE([],[],,align_flag="")
+ CFLAGS="$_SAVE_CFLAGS"
+fi
+
+dnl Use echo to avoid accumulating space characters
+all_flags=`echo $arch_flag $thumb_flag $thumb_interwork_flag $fpu_flag $float_abi_flag $soft_float_flag $align_flag`
+if test -n "$all_flags"; then
+ _SAVE_CFLAGS="$CFLAGS"
+ CFLAGS="$all_flags"
+ AC_MSG_CHECKING(whether the chosen combination of compiler flags ($all_flags) works)
+ AC_TRY_COMPILE([],[return 0;],
+ AC_MSG_RESULT([yes]),
+ AC_MSG_ERROR([no]))
+
+ CFLAGS="$_SAVE_CFLAGS $all_flags"
+ CXXFLAGS="$CXXFLAGS $all_flags"
+ ASFLAGS="$ASFLAGS $all_flags"
+ if test -n "$thumb_flag"; then
+ LDFLAGS="$LDFLAGS $thumb_flag"
+ fi
+fi
+
+AC_SUBST(MOZ_THUMB2)
+
+if test "$CPU_ARCH" = "arm"; then
+ AC_MSG_CHECKING(for ARM SIMD support in compiler)
+ # We try to link so that this also fails when
+ # building with LTO.
+ AC_TRY_LINK([],
+ [asm("uqadd8 r1, r1, r2");],
+ result="yes", result="no")
+ AC_MSG_RESULT("$result")
+ if test "$result" = "yes"; then
+ AC_DEFINE(HAVE_ARM_SIMD)
+ HAVE_ARM_SIMD=1
+ fi
+
+ AC_MSG_CHECKING(ARM version support in compiler)
+ dnl Determine the target ARM architecture (5 for ARMv5, v5T, v5E, etc.; 6 for ARMv6, v6K, etc.)
+ ARM_ARCH=`${CC-cc} ${CFLAGS} -dM -E - < /dev/null | sed -n 's/.*__ARM_ARCH_\([[0-9]][[0-9]]*\).*/\1/p'`
+ AC_MSG_RESULT("$ARM_ARCH")
+
+ AC_MSG_CHECKING(for ARM NEON support in compiler)
+ # We try to link so that this also fails when
+ # building with LTO.
+ AC_TRY_LINK([],
+ [asm(".fpu neon\n vadd.i8 d0, d0, d0");],
+ result="yes", result="no")
+ AC_MSG_RESULT("$result")
+ if test "$result" = "yes"; then
+ AC_DEFINE(HAVE_ARM_NEON)
+ HAVE_ARM_NEON=1
+
+ dnl We don't need to build NEON support if we're targetting a non-NEON device.
+ dnl This matches media/webrtc/trunk/webrtc/build/common.gypi.
+ if test -n "$ARM_ARCH"; then
+ if test "$ARM_ARCH" -lt 7; then
+ BUILD_ARM_NEON=
+ else
+ AC_DEFINE(BUILD_ARM_NEON)
+ BUILD_ARM_NEON=1
+ fi
+ fi
+ fi
+
+fi # CPU_ARCH = arm
+
+AC_SUBST(HAVE_ARM_SIMD)
+AC_SUBST(HAVE_ARM_NEON)
+AC_SUBST(BUILD_ARM_NEON)
+AC_SUBST(ARM_ARCH)
+
+if test -n "$MOZ_ARCH"; then
+ NSPR_CONFIGURE_ARGS="$NSPR_CONFIGURE_ARGS --with-arch=$MOZ_ARCH"
+ NSPR_CONFIGURE_ARGS="$NSPR_CONFIGURE_ARGS --with-thumb=$MOZ_THUMB"
+ NSPR_CONFIGURE_ARGS="$NSPR_CONFIGURE_ARGS --with-thumb-interwork=$MOZ_THUMB_INTERWORK"
+ NSPR_CONFIGURE_ARGS="$NSPR_CONFIGURE_ARGS --with-fpu=$MOZ_FPU"
+ NSPR_CONFIGURE_ARGS="$NSPR_CONFIGURE_ARGS --with-float-abi=$MOZ_FLOAT_ABI"
+ NSPR_CONFIGURE_ARGS="$NSPR_CONFIGURE_ARGS --with-soft-float=$MOZ_SOFT_FLOAT"
+fi
+
+])
diff --git a/src/third_party/mozjs-45/build/autoconf/clang-plugin.m4 b/src/third_party/mozjs-45/build/autoconf/clang-plugin.m4
new file mode 100644
index 0000000..5618a1c
--- /dev/null
+++ b/src/third_party/mozjs-45/build/autoconf/clang-plugin.m4
@@ -0,0 +1,60 @@
+dnl This Source Code Form is subject to the terms of the Mozilla Public
+dnl License, v. 2.0. If a copy of the MPL was not distributed with this
+dnl file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+AC_DEFUN([MOZ_CONFIG_CLANG_PLUGIN], [
+
+MOZ_ARG_ENABLE_BOOL(clang-plugin,
+[ --enable-clang-plugin Enable building with the mozilla clang plugin ],
+ ENABLE_CLANG_PLUGIN=1,
+ ENABLE_CLANG_PLUGIN= )
+if test -n "$ENABLE_CLANG_PLUGIN"; then
+ if test -z "$CLANG_CC"; then
+ AC_MSG_ERROR([Can't use clang plugin without clang.])
+ fi
+
+ AC_MSG_CHECKING([for llvm-config])
+ if test -z "$LLVMCONFIG"; then
+ LLVMCONFIG=`$CXX -print-prog-name=llvm-config`
+ fi
+
+ if test -z "$LLVMCONFIG"; then
+ LLVMCONFIG=`which llvm-config`
+ fi
+
+ if test ! -x "$LLVMCONFIG"; then
+ AC_MSG_RESULT([not found])
+ AC_MSG_ERROR([Cannot find an llvm-config binary for building a clang plugin])
+ fi
+
+ AC_MSG_RESULT([$LLVMCONFIG])
+
+ if test -z "$LLVMCONFIG"; then
+ AC_MSG_ERROR([Cannot find an llvm-config binary for building a clang plugin])
+ fi
+ LLVM_CXXFLAGS=`$LLVMCONFIG --cxxflags`
+ dnl The clang package we use on OSX is old, and its llvm-config doesn't
+ dnl recognize --system-libs, so ask for that separately. llvm-config's
+ dnl failure here is benign, so we can ignore it if it happens.
+ LLVM_LDFLAGS=`$LLVMCONFIG --system-libs | xargs`
+ LLVM_LDFLAGS="$LLVM_LDFLAGS `$LLVMCONFIG --ldflags --libs core mc analysis asmparser mcparser bitreader option | xargs`"
+
+ if test "${HOST_OS_ARCH}" = "Darwin"; then
+ CLANG_LDFLAGS="-lclangFrontend -lclangDriver -lclangSerialization"
+ CLANG_LDFLAGS="$CLANG_LDFLAGS -lclangParse -lclangSema -lclangAnalysis"
+ CLANG_LDFLAGS="$CLANG_LDFLAGS -lclangEdit -lclangAST -lclangLex"
+ CLANG_LDFLAGS="$CLANG_LDFLAGS -lclangBasic -lclangASTMatchers"
+ else
+ CLANG_LDFLAGS="-lclangASTMatchers"
+ fi
+
+ AC_DEFINE(MOZ_CLANG_PLUGIN)
+fi
+
+AC_SUBST(LLVM_CXXFLAGS)
+AC_SUBST(LLVM_LDFLAGS)
+AC_SUBST(CLANG_LDFLAGS)
+
+AC_SUBST(ENABLE_CLANG_PLUGIN)
+
+])
diff --git a/src/third_party/mozjs-45/build/autoconf/clean-config.sh b/src/third_party/mozjs-45/build/autoconf/clean-config.sh
new file mode 100755
index 0000000..2505547
--- /dev/null
+++ b/src/third_party/mozjs-45/build/autoconf/clean-config.sh
@@ -0,0 +1,31 @@
+#!/bin/sh
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+# clean-config.sh - Removes all files generated by mozilla configure.
+# Only removes files from the topsrcdir. To clean up an objdir,
+# simply remove the directory and start over.
+#
+# Usage:
+# 1. cd <topsrcdir>
+# 2. build/autoconf/clean-config.sh
+#
+# Send comments, improvements, bugs to slamm@netscape.com
+
+topsrcdir=`cd \`dirname $0\`/../..; pwd`
+
+if [ ! -f configure.in ]; then
+ echo "clean-config.sh only cleans the source tree. To run," 2>&1
+ echo " cd $topsrcdir; build/autoconf/clean-config.sh" 2>&1
+ echo " (To clean a separate objdir, simple remove the directory.)" 2>&1
+ exit 1
+fi
+
+rm -fr \
+ config-defs.h \
+ config.cache \
+ config.log \
+ config.status \
+ $NULL
diff --git a/src/third_party/mozjs-45/build/autoconf/codeset.m4 b/src/third_party/mozjs-45/build/autoconf/codeset.m4
new file mode 100644
index 0000000..4dc1d50
--- /dev/null
+++ b/src/third_party/mozjs-45/build/autoconf/codeset.m4
@@ -0,0 +1,24 @@
+# codeset.m4 serial AM1 (gettext-0.10.40)
+dnl Copyright (C) 2000-2002 Free Software Foundation, Inc.
+dnl This file is free software, distributed under the terms of the GNU
+dnl General Public License. As a special exception to the GNU General
+dnl Public License, this file may be distributed as part of a program
+dnl that contains a configuration script generated by Autoconf, under
+dnl the same distribution terms as the rest of that program.
+
+dnl From Bruno Haible.
+
+AC_DEFUN([AM_LANGINFO_CODESET],
+[
+ AC_CACHE_CHECK([for nl_langinfo and CODESET], am_cv_langinfo_codeset,
+ [AC_TRY_LINK([#include <langinfo.h>],
+ [char* cs = nl_langinfo(CODESET);],
+ am_cv_langinfo_codeset=yes,
+ am_cv_langinfo_codeset=no)
+ ])
+ if test $am_cv_langinfo_codeset = yes; then
+ AC_DEFINE(HAVE_LANGINFO_CODESET, 1,
+ [Define if you have <langinfo.h> and nl_langinfo(CODESET).])
+ HAVE_LANGINFO_CODESET=1
+ fi
+])
diff --git a/src/third_party/mozjs-45/build/autoconf/compiler-opts.m4 b/src/third_party/mozjs-45/build/autoconf/compiler-opts.m4
new file mode 100644
index 0000000..56d6af4
--- /dev/null
+++ b/src/third_party/mozjs-45/build/autoconf/compiler-opts.m4
@@ -0,0 +1,425 @@
+dnl This Source Code Form is subject to the terms of the Mozilla Public
+dnl License, v. 2.0. If a copy of the MPL was not distributed with this
+dnl file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+dnl Add compiler specific options
+
+AC_DEFUN([MOZ_DEFAULT_COMPILER],
+[
+dnl set DEVELOPER_OPTIONS early; MOZ_DEFAULT_COMPILER is usually the first non-setup directive
+ if test -z "$MOZILLA_OFFICIAL"; then
+ DEVELOPER_OPTIONS=1
+ fi
+ MOZ_ARG_ENABLE_BOOL(release,
+ [ --enable-release Build with more conservative, release engineering-oriented options.
+ This may slow down builds.],
+ DEVELOPER_OPTIONS=,
+ DEVELOPER_OPTIONS=1)
+
+ AC_SUBST(DEVELOPER_OPTIONS)
+
+dnl Default to MSVC for win32 and gcc-4.2 for darwin
+dnl ==============================================================
+if test -z "$CROSS_COMPILE"; then
+case "$target" in
+*-mingw*)
+ if test -z "$CC"; then CC=cl; fi
+ if test -z "$CXX"; then CXX=cl; fi
+ if test -z "$CPP"; then CPP="$CC -E -nologo"; fi
+ if test -z "$CXXCPP"; then CXXCPP="$CXX -TP -E -nologo"; ac_cv_prog_CXXCPP="$CXXCPP"; fi
+ if test -z "$LD"; then LD=link; fi
+ if test -z "$AS"; then
+ case "${target_cpu}" in
+ i*86)
+ AS=ml;
+ ;;
+ x86_64)
+ AS=ml64;
+ ;;
+ esac
+ fi
+ if test -z "$MIDL"; then MIDL=midl; fi
+
+ # need override this flag since we don't use $(LDFLAGS) for this.
+ if test -z "$HOST_LDFLAGS" ; then
+ HOST_LDFLAGS=" "
+ fi
+ ;;
+*-darwin*)
+ # GCC on darwin is based on gcc 4.2 and we don't support it anymore.
+ if test -z "$CC"; then
+ MOZ_PATH_PROGS(CC, clang)
+ fi
+ if test -z "$CXX"; then
+ MOZ_PATH_PROGS(CXX, clang++)
+ fi
+ IS_GCC=$($CC -v 2>&1 | grep gcc)
+ if test -n "$IS_GCC"
+ then
+ echo gcc is known to be broken on OS X, please use clang.
+ echo see http://developer.mozilla.org/en-US/docs/Developer_Guide/Build_Instructions/Mac_OS_X_Prerequisites
+ echo for more information.
+ exit 1
+ fi
+ ;;
+esac
+fi
+])
+
+dnl ============================================================================
+dnl C++ rtti
+dnl We don't use it in the code, but it can be usefull for debugging, so give
+dnl the user the option of enabling it.
+dnl ============================================================================
+AC_DEFUN([MOZ_RTTI],
+[
+MOZ_ARG_ENABLE_BOOL(cpp-rtti,
+[ --enable-cpp-rtti Enable C++ RTTI ],
+[ _MOZ_USE_RTTI=1 ],
+[ _MOZ_USE_RTTI= ])
+
+if test -z "$_MOZ_USE_RTTI"; then
+ if test "$GNU_CC"; then
+ CXXFLAGS="$CXXFLAGS -fno-rtti"
+ else
+ case "$target" in
+ *-mingw*)
+ CXXFLAGS="$CXXFLAGS -GR-"
+ esac
+ fi
+fi
+])
+
+dnl ========================================================
+dnl =
+dnl = Debugging Options
+dnl =
+dnl ========================================================
+AC_DEFUN([MOZ_DEBUGGING_OPTS],
+[
+dnl Debug info is ON by default.
+if test -z "$MOZ_DEBUG_FLAGS"; then
+ if test -n "$_MSC_VER"; then
+ MOZ_DEBUG_FLAGS="-Zi"
+ else
+ MOZ_DEBUG_FLAGS="-g"
+ fi
+fi
+
+AC_SUBST(MOZ_DEBUG_FLAGS)
+
+MOZ_ARG_ENABLE_STRING(debug,
+[ --enable-debug[=DBG] Enable building with developer debug info
+ (using compiler flags DBG)],
+[ if test "$enableval" != "no"; then
+ MOZ_DEBUG=1
+ if test -n "$enableval" -a "$enableval" != "yes"; then
+ MOZ_DEBUG_FLAGS=`echo $enableval | sed -e 's|\\\ | |g'`
+ _MOZ_DEBUG_FLAGS_SET=1
+ fi
+ else
+ MOZ_DEBUG=
+ fi ],
+ MOZ_DEBUG=)
+
+if test -z "$MOZ_DEBUG" -o -n "$MOZ_ASAN"; then
+ MOZ_NO_DEBUG_RTL=1
+fi
+
+AC_SUBST(MOZ_NO_DEBUG_RTL)
+
+MOZ_DEBUG_ENABLE_DEFS="-DDEBUG -DTRACING"
+MOZ_ARG_WITH_STRING(debug-label,
+[ --with-debug-label=LABELS
+ Define DEBUG_<value> for each comma-separated
+ value given.],
+[ for option in `echo $withval | sed 's/,/ /g'`; do
+ MOZ_DEBUG_ENABLE_DEFS="$MOZ_DEBUG_ENABLE_DEFS -DDEBUG_${option}"
+done])
+
+if test -n "$MOZ_DEBUG"; then
+ AC_MSG_CHECKING([for valid debug flags])
+ _SAVE_CFLAGS=$CFLAGS
+ CFLAGS="$CFLAGS $MOZ_DEBUG_FLAGS"
+ AC_TRY_COMPILE([#include <stdio.h>],
+ [printf("Hello World\n");],
+ _results=yes,
+ _results=no)
+ AC_MSG_RESULT([$_results])
+ if test "$_results" = "no"; then
+ AC_MSG_ERROR([These compiler flags are invalid: $MOZ_DEBUG_FLAGS])
+ fi
+ CFLAGS=$_SAVE_CFLAGS
+
+ MOZ_DEBUG_DEFINES="$MOZ_DEBUG_ENABLE_DEFS"
+else
+ MOZ_DEBUG_DEFINES="-DNDEBUG -DTRIMMED"
+fi
+
+AC_SUBST(MOZ_DEBUG_DEFINES)
+
+dnl ========================================================
+dnl = Enable generation of debug symbols
+dnl ========================================================
+MOZ_ARG_ENABLE_STRING(debug-symbols,
+[ --enable-debug-symbols[=DBG]
+ Enable debugging symbols (using compiler flags DBG)],
+[ if test "$enableval" != "no"; then
+ MOZ_DEBUG_SYMBOLS=1
+ if test -n "$enableval" -a "$enableval" != "yes"; then
+ if test -z "$_MOZ_DEBUG_FLAGS_SET"; then
+ MOZ_DEBUG_FLAGS=`echo $enableval | sed -e 's|\\\ | |g'`
+ else
+ AC_MSG_ERROR([--enable-debug-symbols flags cannot be used with --enable-debug flags])
+ fi
+ fi
+ else
+ MOZ_DEBUG_SYMBOLS=
+ fi ],
+ MOZ_DEBUG_SYMBOLS=1)
+
+if test -n "$MOZ_DEBUG" -o -n "$MOZ_DEBUG_SYMBOLS"; then
+ AC_DEFINE(MOZ_DEBUG_SYMBOLS)
+ export MOZ_DEBUG_SYMBOLS
+fi
+
+])
+
+dnl A high level macro for selecting compiler options.
+AC_DEFUN([MOZ_COMPILER_OPTS],
+[
+ MOZ_DEBUGGING_OPTS
+ MOZ_RTTI
+if test "$CLANG_CXX"; then
+ ## We disable return-type-c-linkage because jsval is defined as a C++ type but is
+ ## returned by C functions. This is possible because we use knowledge about the ABI
+ ## to typedef it to a C type with the same layout when the headers are included
+ ## from C.
+ _WARNINGS_CXXFLAGS="${_WARNINGS_CXXFLAGS} -Wno-unknown-warning-option -Wno-return-type-c-linkage"
+fi
+
+AC_MSG_CHECKING([whether the C++ compiler ($CXX $CXXFLAGS $LDFLAGS) actually is a C++ compiler])
+AC_LANG_SAVE
+AC_LANG_CPLUSPLUS
+_SAVE_LIBS=$LIBS
+LIBS=
+AC_TRY_LINK([#include <new>], [int *foo = new int;],,
+ AC_MSG_RESULT([no])
+ AC_MSG_ERROR([$CXX $CXXFLAGS $LDFLAGS failed to compile and link a simple C++ source.]))
+LIBS=$_SAVE_LIBS
+AC_LANG_RESTORE
+AC_MSG_RESULT([yes])
+
+if test -n "$DEVELOPER_OPTIONS"; then
+ MOZ_FORCE_GOLD=1
+fi
+
+MOZ_ARG_ENABLE_BOOL(gold,
+[ --enable-gold Enable GNU Gold Linker when it is not already the default],
+ MOZ_FORCE_GOLD=1,
+ MOZ_FORCE_GOLD=
+ )
+
+if test "$GNU_CC" -a -n "$MOZ_FORCE_GOLD"; then
+ dnl if the default linker is BFD ld, check if gold is available and try to use it
+ dnl for local builds only.
+ if $CC -Wl,--version 2>&1 | grep -q "GNU ld"; then
+ GOLD=$($CC -print-prog-name=ld.gold)
+ case "$GOLD" in
+ /*)
+ ;;
+ *)
+ GOLD=$(which $GOLD)
+ ;;
+ esac
+ if test -n "$GOLD"; then
+ mkdir -p $_objdir/build/unix/gold
+ rm -f $_objdir/build/unix/gold/ld
+ ln -s "$GOLD" $_objdir/build/unix/gold/ld
+ if $CC -B $_objdir/build/unix/gold -Wl,--version 2>&1 | grep -q "GNU gold"; then
+ LDFLAGS="$LDFLAGS -B $_objdir/build/unix/gold"
+ else
+ rm -rf $_objdir/build/unix/gold
+ fi
+ fi
+ fi
+fi
+if test "$GNU_CC"; then
+ if $CC $LDFLAGS -Wl,--version 2>&1 | grep -q "GNU ld"; then
+ LD_IS_BFD=1
+ fi
+fi
+
+AC_SUBST([LD_IS_BFD])
+
+if test "$GNU_CC"; then
+ if test -z "$DEVELOPER_OPTIONS"; then
+ CFLAGS="$CFLAGS -ffunction-sections -fdata-sections"
+ CXXFLAGS="$CXXFLAGS -ffunction-sections -fdata-sections"
+ fi
+ CFLAGS="$CFLAGS -fno-math-errno"
+ CXXFLAGS="$CXXFLAGS -fno-exceptions -fno-math-errno"
+fi
+
+dnl ========================================================
+dnl = Identical Code Folding
+dnl ========================================================
+
+MOZ_ARG_DISABLE_BOOL(icf,
+[ --disable-icf Disable Identical Code Folding],
+ MOZ_DISABLE_ICF=1,
+ MOZ_DISABLE_ICF= )
+
+if test "$GNU_CC" -a "$GCC_USE_GNU_LD" -a -z "$MOZ_DISABLE_ICF" -a -z "$DEVELOPER_OPTIONS"; then
+ AC_CACHE_CHECK([whether the linker supports Identical Code Folding],
+ LD_SUPPORTS_ICF,
+ [echo 'int foo() {return 42;}' \
+ 'int bar() {return 42;}' \
+ 'int main() {return foo() - bar();}' > conftest.${ac_ext}
+ # If the linker supports ICF, foo and bar symbols will have
+ # the same address
+ if AC_TRY_COMMAND([${CC-cc} -o conftest${ac_exeext} $LDFLAGS -Wl,--icf=safe -ffunction-sections conftest.${ac_ext} $LIBS 1>&2]) &&
+ test -s conftest${ac_exeext} &&
+ objdump -t conftest${ac_exeext} | awk changequote(<<, >>)'{a[<<$>>6] = <<$>>1} END {if (a["foo"] && (a["foo"] != a["bar"])) { exit 1 }}'changequote([, ]); then
+ LD_SUPPORTS_ICF=yes
+ else
+ LD_SUPPORTS_ICF=no
+ fi
+ rm -rf conftest*])
+ if test "$LD_SUPPORTS_ICF" = yes; then
+ _SAVE_LDFLAGS="$LDFLAGS -Wl,--icf=safe"
+ LDFLAGS="$LDFLAGS -Wl,--icf=safe -Wl,--print-icf-sections"
+ AC_TRY_LINK([], [],
+ [LD_PRINT_ICF_SECTIONS=-Wl,--print-icf-sections],
+ [LD_PRINT_ICF_SECTIONS=])
+ AC_SUBST([LD_PRINT_ICF_SECTIONS])
+ LDFLAGS="$_SAVE_LDFLAGS"
+ fi
+fi
+
+dnl ========================================================
+dnl = Automatically remove dead symbols
+dnl ========================================================
+
+if test "$GNU_CC" -a "$GCC_USE_GNU_LD" -a -z "$DEVELOPER_OPTIONS"; then
+ if test -n "$MOZ_DEBUG_FLAGS"; then
+ dnl See bug 670659
+ AC_CACHE_CHECK([whether removing dead symbols breaks debugging],
+ GC_SECTIONS_BREAKS_DEBUG_RANGES,
+ [echo 'int foo() {return 42;}' \
+ 'int bar() {return 1;}' \
+ 'int main() {return foo();}' > conftest.${ac_ext}
+ if AC_TRY_COMMAND([${CC-cc} -o conftest.${ac_objext} $CFLAGS $MOZ_DEBUG_FLAGS -c conftest.${ac_ext} 1>&2]) &&
+ AC_TRY_COMMAND([${CC-cc} -o conftest${ac_exeext} $LDFLAGS $MOZ_DEBUG_FLAGS -Wl,--gc-sections conftest.${ac_objext} $LIBS 1>&2]) &&
+ test -s conftest${ac_exeext} -a -s conftest.${ac_objext}; then
+ if test "`$PYTHON -m mozbuild.configure.check_debug_ranges conftest.${ac_objext} conftest.${ac_ext}`" = \
+ "`$PYTHON -m mozbuild.configure.check_debug_ranges conftest${ac_exeext} conftest.${ac_ext}`"; then
+ GC_SECTIONS_BREAKS_DEBUG_RANGES=no
+ else
+ GC_SECTIONS_BREAKS_DEBUG_RANGES=yes
+ fi
+ else
+ dnl We really don't expect to get here, but just in case
+ GC_SECTIONS_BREAKS_DEBUG_RANGES="no, but it's broken in some other way"
+ fi
+ rm -rf conftest*])
+ if test "$GC_SECTIONS_BREAKS_DEBUG_RANGES" = no; then
+ DSO_LDOPTS="$DSO_LDOPTS -Wl,--gc-sections"
+ fi
+ else
+ DSO_LDOPTS="$DSO_LDOPTS -Wl,--gc-sections"
+ fi
+fi
+
+# bionic in Android < 4.1 doesn't support PIE
+# On OSX, the linker defaults to building PIE programs when targetting OSX 10.7+,
+# but not when targetting OSX < 10.7. OSX < 10.7 doesn't support running PIE
+# programs, so as long as support for OSX 10.6 is kept, we can't build PIE.
+# Even after dropping 10.6 support, MOZ_PIE would not be useful since it's the
+# default (and clang says the -pie option is not used).
+# On other Unix systems, some file managers (Nautilus) can't start PIE programs
+if test -n "$gonkdir" && test "$ANDROID_VERSION" -ge 16; then
+ MOZ_PIE=1
+else
+ MOZ_PIE=
+fi
+
+MOZ_ARG_ENABLE_BOOL(pie,
+[ --enable-pie Enable Position Independent Executables],
+ MOZ_PIE=1,
+ MOZ_PIE= )
+
+if test "$GNU_CC" -a -n "$MOZ_PIE"; then
+ AC_MSG_CHECKING([for PIE support])
+ _SAVE_LDFLAGS=$LDFLAGS
+ LDFLAGS="$LDFLAGS -pie"
+ AC_TRY_LINK(,,AC_MSG_RESULT([yes])
+ [MOZ_PROGRAM_LDFLAGS="$MOZ_PROGRAM_LDFLAGS -pie"],
+ AC_MSG_RESULT([no])
+ AC_MSG_ERROR([--enable-pie requires PIE support from the linker.]))
+ LDFLAGS=$_SAVE_LDFLAGS
+fi
+
+AC_SUBST(MOZ_PROGRAM_LDFLAGS)
+
+dnl ASan assumes no symbols are being interposed, and when that happens,
+dnl it's not happy with it. Unconveniently, since Firefox is exporting
+dnl libffi symbols and Gtk+3 pulls system libffi via libwayland-client,
+dnl system libffi interposes libffi symbols that ASan assumes are in
+dnl libxul, so it barfs about buffer overflows.
+dnl Using -Wl,-Bsymbolic ensures no exported symbol can be interposed.
+if test -n "$GCC_USE_GNU_LD"; then
+ case "$LDFLAGS" in
+ *-fsanitize=address*)
+ LDFLAGS="$LDFLAGS -Wl,-Bsymbolic"
+ ;;
+ esac
+fi
+
+])
+
+dnl GCC and clang will fail if given an unknown warning option like -Wfoobar.
+dnl But later versions won't fail if given an unknown negated warning option
+dnl like -Wno-foobar. So when we are check for support of negated warning
+dnl options, we actually test the positive form, but add the negated form to
+dnl the flags variable.
+
+AC_DEFUN([MOZ_C_SUPPORTS_WARNING],
+[
+ AC_CACHE_CHECK(whether the C compiler supports $1$2, $3,
+ [
+ AC_LANG_SAVE
+ AC_LANG_C
+ _SAVE_CFLAGS="$CFLAGS"
+ CFLAGS="$CFLAGS -Werror -W$2"
+ AC_TRY_COMPILE([],
+ [return(0);],
+ $3="yes",
+ $3="no")
+ CFLAGS="$_SAVE_CFLAGS"
+ AC_LANG_RESTORE
+ ])
+ if test "${$3}" = "yes"; then
+ _WARNINGS_CFLAGS="${_WARNINGS_CFLAGS} $1$2"
+ fi
+])
+
+AC_DEFUN([MOZ_CXX_SUPPORTS_WARNING],
+[
+ AC_CACHE_CHECK(whether the C++ compiler supports $1$2, $3,
+ [
+ AC_LANG_SAVE
+ AC_LANG_CPLUSPLUS
+ _SAVE_CXXFLAGS="$CXXFLAGS"
+ CXXFLAGS="$CXXFLAGS -Werror -W$2"
+ AC_TRY_COMPILE([],
+ [return(0);],
+ $3="yes",
+ $3="no")
+ CXXFLAGS="$_SAVE_CXXFLAGS"
+ AC_LANG_RESTORE
+ ])
+ if test "${$3}" = "yes"; then
+ _WARNINGS_CXXFLAGS="${_WARNINGS_CXXFLAGS} $1$2"
+ fi
+])
diff --git a/src/third_party/mozjs-45/build/autoconf/config.guess b/src/third_party/mozjs-45/build/autoconf/config.guess
new file mode 100755
index 0000000..72625d4
--- /dev/null
+++ b/src/third_party/mozjs-45/build/autoconf/config.guess
@@ -0,0 +1,1420 @@
+#! /bin/sh
+# Attempt to guess a canonical system name.
+# Copyright 1992-2014 Free Software Foundation, Inc.
+
+timestamp='2014-02-12'
+
+# This file is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, see <http://www.gnu.org/licenses/>.
+#
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that
+# program. This Exception is an additional permission under section 7
+# of the GNU General Public License, version 3 ("GPLv3").
+#
+# Originally written by Per Bothner.
+#
+# You can get the latest version of this script from:
+# http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess;hb=HEAD
+#
+# Please send patches with a ChangeLog entry to config-patches@gnu.org.
+
+
+me=`echo "$0" | sed -e 's,.*/,,'`
+
+usage="\
+Usage: $0 [OPTION]
+
+Output the configuration name of the system \`$me' is run on.
+
+Operation modes:
+ -h, --help print this help, then exit
+ -t, --time-stamp print date of last modification, then exit
+ -v, --version print version number, then exit
+
+Report bugs and patches to <config-patches@gnu.org>."
+
+version="\
+GNU config.guess ($timestamp)
+
+Originally written by Per Bothner.
+Copyright 1992-2014 Free Software Foundation, Inc.
+
+This is free software; see the source for copying conditions. There is NO
+warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."
+
+help="
+Try \`$me --help' for more information."
+
+# Parse command line
+while test $# -gt 0 ; do
+ case $1 in
+ --time-stamp | --time* | -t )
+ echo "$timestamp" ; exit ;;
+ --version | -v )
+ echo "$version" ; exit ;;
+ --help | --h* | -h )
+ echo "$usage"; exit ;;
+ -- ) # Stop option processing
+ shift; break ;;
+ - ) # Use stdin as input.
+ break ;;
+ -* )
+ echo "$me: invalid option $1$help" >&2
+ exit 1 ;;
+ * )
+ break ;;
+ esac
+done
+
+if test $# != 0; then
+ echo "$me: too many arguments$help" >&2
+ exit 1
+fi
+
+trap 'exit 1' 1 2 15
+
+# CC_FOR_BUILD -- compiler used by this script. Note that the use of a
+# compiler to aid in system detection is discouraged as it requires
+# temporary files to be created and, as you can see below, it is a
+# headache to deal with in a portable fashion.
+
+# Historically, `CC_FOR_BUILD' used to be named `HOST_CC'. We still
+# use `HOST_CC' if defined, but it is deprecated.
+
+# Portable tmp directory creation inspired by the Autoconf team.
+
+set_cc_for_build='
+trap "exitcode=\$?; (rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null) && exit \$exitcode" 0 ;
+trap "rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null; exit 1" 1 2 13 15 ;
+: ${TMPDIR=/tmp} ;
+ { tmp=`(umask 077 && mktemp -d "$TMPDIR/cgXXXXXX") 2>/dev/null` && test -n "$tmp" && test -d "$tmp" ; } ||
+ { test -n "$RANDOM" && tmp=$TMPDIR/cg$$-$RANDOM && (umask 077 && mkdir $tmp) ; } ||
+ { tmp=$TMPDIR/cg-$$ && (umask 077 && mkdir $tmp) && echo "Warning: creating insecure temp directory" >&2 ; } ||
+ { echo "$me: cannot create a temporary directory in $TMPDIR" >&2 ; exit 1 ; } ;
+dummy=$tmp/dummy ;
+tmpfiles="$dummy.c $dummy.o $dummy.rel $dummy" ;
+case $CC_FOR_BUILD,$HOST_CC,$CC in
+ ,,) echo "int x;" > $dummy.c ;
+ for c in cc gcc c89 c99 ; do
+ if ($c -c -o $dummy.o $dummy.c) >/dev/null 2>&1 ; then
+ CC_FOR_BUILD="$c"; break ;
+ fi ;
+ done ;
+ if test x"$CC_FOR_BUILD" = x ; then
+ CC_FOR_BUILD=no_compiler_found ;
+ fi
+ ;;
+ ,,*) CC_FOR_BUILD=$CC ;;
+ ,*,*) CC_FOR_BUILD=$HOST_CC ;;
+esac ; set_cc_for_build= ;'
+
+# This is needed to find uname on a Pyramid OSx when run in the BSD universe.
+# (ghazi@noc.rutgers.edu 1994-08-24)
+if (test -f /.attbin/uname) >/dev/null 2>&1 ; then
+ PATH=$PATH:/.attbin ; export PATH
+fi
+
+UNAME_MACHINE=`(uname -m) 2>/dev/null` || UNAME_MACHINE=unknown
+UNAME_RELEASE=`(uname -r) 2>/dev/null` || UNAME_RELEASE=unknown
+UNAME_SYSTEM=`(uname -s) 2>/dev/null` || UNAME_SYSTEM=unknown
+UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown
+
+case "${UNAME_SYSTEM}" in
+Linux|GNU|GNU/*)
+ # If the system lacks a compiler, then just pick glibc.
+ # We could probably try harder.
+ LIBC=gnu
+
+ eval $set_cc_for_build
+ cat <<-EOF > $dummy.c
+ #include <features.h>
+ #if defined(__UCLIBC__)
+ LIBC=uclibc
+ #elif defined(__dietlibc__)
+ LIBC=dietlibc
+ #else
+ LIBC=gnu
+ #endif
+ EOF
+ eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^LIBC' | sed 's, ,,g'`
+ ;;
+esac
+
+# Note: order is significant - the case branches are not exclusive.
+
+case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in
+ *:NetBSD:*:*)
+ # NetBSD (nbsd) targets should (where applicable) match one or
+ # more of the tuples: *-*-netbsdelf*, *-*-netbsdaout*,
+ # *-*-netbsdecoff* and *-*-netbsd*. For targets that recently
+ # switched to ELF, *-*-netbsd* would select the old
+ # object file format. This provides both forward
+ # compatibility and a consistent mechanism for selecting the
+ # object file format.
+ #
+ # Note: NetBSD doesn't particularly care about the vendor
+ # portion of the name. We always set it to "unknown".
+ sysctl="sysctl -n hw.machine_arch"
+ UNAME_MACHINE_ARCH=`(/sbin/$sysctl 2>/dev/null || \
+ /usr/sbin/$sysctl 2>/dev/null || echo unknown)`
+ case "${UNAME_MACHINE_ARCH}" in
+ armeb) machine=armeb-unknown ;;
+ arm*) machine=arm-unknown ;;
+ sh3el) machine=shl-unknown ;;
+ sh3eb) machine=sh-unknown ;;
+ sh5el) machine=sh5le-unknown ;;
+ *) machine=${UNAME_MACHINE_ARCH}-unknown ;;
+ esac
+ # The Operating System including object format, if it has switched
+ # to ELF recently, or will in the future.
+ case "${UNAME_MACHINE_ARCH}" in
+ arm*|i386|m68k|ns32k|sh3*|sparc|vax)
+ eval $set_cc_for_build
+ if echo __ELF__ | $CC_FOR_BUILD -E - 2>/dev/null \
+ | grep -q __ELF__
+ then
+ # Once all utilities can be ECOFF (netbsdecoff) or a.out (netbsdaout).
+ # Return netbsd for either. FIX?
+ os=netbsd
+ else
+ os=netbsdelf
+ fi
+ ;;
+ *)
+ os=netbsd
+ ;;
+ esac
+ # The OS release
+ # Debian GNU/NetBSD machines have a different userland, and
+ # thus, need a distinct triplet. However, they do not need
+ # kernel version information, so it can be replaced with a
+ # suitable tag, in the style of linux-gnu.
+ case "${UNAME_VERSION}" in
+ Debian*)
+ release='-gnu'
+ ;;
+ *)
+ release=`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'`
+ ;;
+ esac
+ # Since CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM:
+ # contains redundant information, the shorter form:
+ # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM is used.
+ echo "${machine}-${os}${release}"
+ exit ;;
+ *:Bitrig:*:*)
+ UNAME_MACHINE_ARCH=`arch | sed 's/Bitrig.//'`
+ echo ${UNAME_MACHINE_ARCH}-unknown-bitrig${UNAME_RELEASE}
+ exit ;;
+ *:OpenBSD:*:*)
+ UNAME_MACHINE_ARCH=`arch | sed 's/OpenBSD.//'`
+ echo ${UNAME_MACHINE_ARCH}-unknown-openbsd${UNAME_RELEASE}
+ exit ;;
+ *:ekkoBSD:*:*)
+ echo ${UNAME_MACHINE}-unknown-ekkobsd${UNAME_RELEASE}
+ exit ;;
+ *:SolidBSD:*:*)
+ echo ${UNAME_MACHINE}-unknown-solidbsd${UNAME_RELEASE}
+ exit ;;
+ macppc:MirBSD:*:*)
+ echo powerpc-unknown-mirbsd${UNAME_RELEASE}
+ exit ;;
+ *:MirBSD:*:*)
+ echo ${UNAME_MACHINE}-unknown-mirbsd${UNAME_RELEASE}
+ exit ;;
+ alpha:OSF1:*:*)
+ case $UNAME_RELEASE in
+ *4.0)
+ UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'`
+ ;;
+ *5.*)
+ UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $4}'`
+ ;;
+ esac
+ # According to Compaq, /usr/sbin/psrinfo has been available on
+ # OSF/1 and Tru64 systems produced since 1995. I hope that
+ # covers most systems running today. This code pipes the CPU
+ # types through head -n 1, so we only detect the type of CPU 0.
+ ALPHA_CPU_TYPE=`/usr/sbin/psrinfo -v | sed -n -e 's/^ The alpha \(.*\) processor.*$/\1/p' | head -n 1`
+ case "$ALPHA_CPU_TYPE" in
+ "EV4 (21064)")
+ UNAME_MACHINE="alpha" ;;
+ "EV4.5 (21064)")
+ UNAME_MACHINE="alpha" ;;
+ "LCA4 (21066/21068)")
+ UNAME_MACHINE="alpha" ;;
+ "EV5 (21164)")
+ UNAME_MACHINE="alphaev5" ;;
+ "EV5.6 (21164A)")
+ UNAME_MACHINE="alphaev56" ;;
+ "EV5.6 (21164PC)")
+ UNAME_MACHINE="alphapca56" ;;
+ "EV5.7 (21164PC)")
+ UNAME_MACHINE="alphapca57" ;;
+ "EV6 (21264)")
+ UNAME_MACHINE="alphaev6" ;;
+ "EV6.7 (21264A)")
+ UNAME_MACHINE="alphaev67" ;;
+ "EV6.8CB (21264C)")
+ UNAME_MACHINE="alphaev68" ;;
+ "EV6.8AL (21264B)")
+ UNAME_MACHINE="alphaev68" ;;
+ "EV6.8CX (21264D)")
+ UNAME_MACHINE="alphaev68" ;;
+ "EV6.9A (21264/EV69A)")
+ UNAME_MACHINE="alphaev69" ;;
+ "EV7 (21364)")
+ UNAME_MACHINE="alphaev7" ;;
+ "EV7.9 (21364A)")
+ UNAME_MACHINE="alphaev79" ;;
+ esac
+ # A Pn.n version is a patched version.
+ # A Vn.n version is a released version.
+ # A Tn.n version is a released field test version.
+ # A Xn.n version is an unreleased experimental baselevel.
+ # 1.2 uses "1.2" for uname -r.
+ echo ${UNAME_MACHINE}-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[PVTX]//' | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'`
+ # Reset EXIT trap before exiting to avoid spurious non-zero exit code.
+ exitcode=$?
+ trap '' 0
+ exit $exitcode ;;
+ Alpha\ *:Windows_NT*:*)
+ # How do we know it's Interix rather than the generic POSIX subsystem?
+ # Should we change UNAME_MACHINE based on the output of uname instead
+ # of the specific Alpha model?
+ echo alpha-pc-interix
+ exit ;;
+ 21064:Windows_NT:50:3)
+ echo alpha-dec-winnt3.5
+ exit ;;
+ Amiga*:UNIX_System_V:4.0:*)
+ echo m68k-unknown-sysv4
+ exit ;;
+ *:[Aa]miga[Oo][Ss]:*:*)
+ echo ${UNAME_MACHINE}-unknown-amigaos
+ exit ;;
+ *:[Mm]orph[Oo][Ss]:*:*)
+ echo ${UNAME_MACHINE}-unknown-morphos
+ exit ;;
+ *:OS/390:*:*)
+ echo i370-ibm-openedition
+ exit ;;
+ *:z/VM:*:*)
+ echo s390-ibm-zvmoe
+ exit ;;
+ *:OS400:*:*)
+ echo powerpc-ibm-os400
+ exit ;;
+ arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*)
+ echo arm-acorn-riscix${UNAME_RELEASE}
+ exit ;;
+ arm*:riscos:*:*|arm*:RISCOS:*:*)
+ echo arm-unknown-riscos
+ exit ;;
+ SR2?01:HI-UX/MPP:*:* | SR8000:HI-UX/MPP:*:*)
+ echo hppa1.1-hitachi-hiuxmpp
+ exit ;;
+ Pyramid*:OSx*:*:* | MIS*:OSx*:*:* | MIS*:SMP_DC-OSx*:*:*)
+ # akee@wpdis03.wpafb.af.mil (Earle F. Ake) contributed MIS and NILE.
+ if test "`(/bin/universe) 2>/dev/null`" = att ; then
+ echo pyramid-pyramid-sysv3
+ else
+ echo pyramid-pyramid-bsd
+ fi
+ exit ;;
+ NILE*:*:*:dcosx)
+ echo pyramid-pyramid-svr4
+ exit ;;
+ DRS?6000:unix:4.0:6*)
+ echo sparc-icl-nx6
+ exit ;;
+ DRS?6000:UNIX_SV:4.2*:7* | DRS?6000:isis:4.2*:7*)
+ case `/usr/bin/uname -p` in
+ sparc) echo sparc-icl-nx7; exit ;;
+ esac ;;
+ s390x:SunOS:*:*)
+ echo ${UNAME_MACHINE}-ibm-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+ exit ;;
+ sun4H:SunOS:5.*:*)
+ echo sparc-hal-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+ exit ;;
+ sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*)
+ echo sparc-sun-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+ exit ;;
+ i86pc:AuroraUX:5.*:* | i86xen:AuroraUX:5.*:*)
+ echo i386-pc-auroraux${UNAME_RELEASE}
+ exit ;;
+ i86pc:SunOS:5.*:* | i86xen:SunOS:5.*:*)
+ eval $set_cc_for_build
+ SUN_ARCH="i386"
+ # If there is a compiler, see if it is configured for 64-bit objects.
+ # Note that the Sun cc does not turn __LP64__ into 1 like gcc does.
+ # This test works for both compilers.
+ if [ "$CC_FOR_BUILD" != 'no_compiler_found' ]; then
+ if (echo '#ifdef __amd64'; echo IS_64BIT_ARCH; echo '#endif') | \
+ (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | \
+ grep IS_64BIT_ARCH >/dev/null
+ then
+ SUN_ARCH="x86_64"
+ fi
+ fi
+ echo ${SUN_ARCH}-pc-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+ exit ;;
+ sun4*:SunOS:6*:*)
+ # According to config.sub, this is the proper way to canonicalize
+ # SunOS6. Hard to guess exactly what SunOS6 will be like, but
+ # it's likely to be more like Solaris than SunOS4.
+ echo sparc-sun-solaris3`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+ exit ;;
+ sun4*:SunOS:*:*)
+ case "`/usr/bin/arch -k`" in
+ Series*|S4*)
+ UNAME_RELEASE=`uname -v`
+ ;;
+ esac
+ # Japanese Language versions have a version number like `4.1.3-JL'.
+ echo sparc-sun-sunos`echo ${UNAME_RELEASE}|sed -e 's/-/_/'`
+ exit ;;
+ sun3*:SunOS:*:*)
+ echo m68k-sun-sunos${UNAME_RELEASE}
+ exit ;;
+ sun*:*:4.2BSD:*)
+ UNAME_RELEASE=`(sed 1q /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null`
+ test "x${UNAME_RELEASE}" = "x" && UNAME_RELEASE=3
+ case "`/bin/arch`" in
+ sun3)
+ echo m68k-sun-sunos${UNAME_RELEASE}
+ ;;
+ sun4)
+ echo sparc-sun-sunos${UNAME_RELEASE}
+ ;;
+ esac
+ exit ;;
+ aushp:SunOS:*:*)
+ echo sparc-auspex-sunos${UNAME_RELEASE}
+ exit ;;
+ # The situation for MiNT is a little confusing. The machine name
+ # can be virtually everything (everything which is not
+ # "atarist" or "atariste" at least should have a processor
+ # > m68000). The system name ranges from "MiNT" over "FreeMiNT"
+ # to the lowercase version "mint" (or "freemint"). Finally
+ # the system name "TOS" denotes a system which is actually not
+ # MiNT. But MiNT is downward compatible to TOS, so this should
+ # be no problem.
+ atarist[e]:*MiNT:*:* | atarist[e]:*mint:*:* | atarist[e]:*TOS:*:*)
+ echo m68k-atari-mint${UNAME_RELEASE}
+ exit ;;
+ atari*:*MiNT:*:* | atari*:*mint:*:* | atarist[e]:*TOS:*:*)
+ echo m68k-atari-mint${UNAME_RELEASE}
+ exit ;;
+ *falcon*:*MiNT:*:* | *falcon*:*mint:*:* | *falcon*:*TOS:*:*)
+ echo m68k-atari-mint${UNAME_RELEASE}
+ exit ;;
+ milan*:*MiNT:*:* | milan*:*mint:*:* | *milan*:*TOS:*:*)
+ echo m68k-milan-mint${UNAME_RELEASE}
+ exit ;;
+ hades*:*MiNT:*:* | hades*:*mint:*:* | *hades*:*TOS:*:*)
+ echo m68k-hades-mint${UNAME_RELEASE}
+ exit ;;
+ *:*MiNT:*:* | *:*mint:*:* | *:*TOS:*:*)
+ echo m68k-unknown-mint${UNAME_RELEASE}
+ exit ;;
+ m68k:machten:*:*)
+ echo m68k-apple-machten${UNAME_RELEASE}
+ exit ;;
+ powerpc:machten:*:*)
+ echo powerpc-apple-machten${UNAME_RELEASE}
+ exit ;;
+ RISC*:Mach:*:*)
+ echo mips-dec-mach_bsd4.3
+ exit ;;
+ RISC*:ULTRIX:*:*)
+ echo mips-dec-ultrix${UNAME_RELEASE}
+ exit ;;
+ VAX*:ULTRIX*:*:*)
+ echo vax-dec-ultrix${UNAME_RELEASE}
+ exit ;;
+ 2020:CLIX:*:* | 2430:CLIX:*:*)
+ echo clipper-intergraph-clix${UNAME_RELEASE}
+ exit ;;
+ mips:*:*:UMIPS | mips:*:*:RISCos)
+ eval $set_cc_for_build
+ sed 's/^ //' << EOF >$dummy.c
+#ifdef __cplusplus
+#include <stdio.h> /* for printf() prototype */
+ int main (int argc, char *argv[]) {
+#else
+ int main (argc, argv) int argc; char *argv[]; {
+#endif
+ #if defined (host_mips) && defined (MIPSEB)
+ #if defined (SYSTYPE_SYSV)
+ printf ("mips-mips-riscos%ssysv\n", argv[1]); exit (0);
+ #endif
+ #if defined (SYSTYPE_SVR4)
+ printf ("mips-mips-riscos%ssvr4\n", argv[1]); exit (0);
+ #endif
+ #if defined (SYSTYPE_BSD43) || defined(SYSTYPE_BSD)
+ printf ("mips-mips-riscos%sbsd\n", argv[1]); exit (0);
+ #endif
+ #endif
+ exit (-1);
+ }
+EOF
+ $CC_FOR_BUILD -o $dummy $dummy.c &&
+ dummyarg=`echo "${UNAME_RELEASE}" | sed -n 's/\([0-9]*\).*/\1/p'` &&
+ SYSTEM_NAME=`$dummy $dummyarg` &&
+ { echo "$SYSTEM_NAME"; exit; }
+ echo mips-mips-riscos${UNAME_RELEASE}
+ exit ;;
+ Motorola:PowerMAX_OS:*:*)
+ echo powerpc-motorola-powermax
+ exit ;;
+ Motorola:*:4.3:PL8-*)
+ echo powerpc-harris-powermax
+ exit ;;
+ Night_Hawk:*:*:PowerMAX_OS | Synergy:PowerMAX_OS:*:*)
+ echo powerpc-harris-powermax
+ exit ;;
+ Night_Hawk:Power_UNIX:*:*)
+ echo powerpc-harris-powerunix
+ exit ;;
+ m88k:CX/UX:7*:*)
+ echo m88k-harris-cxux7
+ exit ;;
+ m88k:*:4*:R4*)
+ echo m88k-motorola-sysv4
+ exit ;;
+ m88k:*:3*:R3*)
+ echo m88k-motorola-sysv3
+ exit ;;
+ AViiON:dgux:*:*)
+ # DG/UX returns AViiON for all architectures
+ UNAME_PROCESSOR=`/usr/bin/uname -p`
+ if [ $UNAME_PROCESSOR = mc88100 ] || [ $UNAME_PROCESSOR = mc88110 ]
+ then
+ if [ ${TARGET_BINARY_INTERFACE}x = m88kdguxelfx ] || \
+ [ ${TARGET_BINARY_INTERFACE}x = x ]
+ then
+ echo m88k-dg-dgux${UNAME_RELEASE}
+ else
+ echo m88k-dg-dguxbcs${UNAME_RELEASE}
+ fi
+ else
+ echo i586-dg-dgux${UNAME_RELEASE}
+ fi
+ exit ;;
+ M88*:DolphinOS:*:*) # DolphinOS (SVR3)
+ echo m88k-dolphin-sysv3
+ exit ;;
+ M88*:*:R3*:*)
+ # Delta 88k system running SVR3
+ echo m88k-motorola-sysv3
+ exit ;;
+ XD88*:*:*:*) # Tektronix XD88 system running UTekV (SVR3)
+ echo m88k-tektronix-sysv3
+ exit ;;
+ Tek43[0-9][0-9]:UTek:*:*) # Tektronix 4300 system running UTek (BSD)
+ echo m68k-tektronix-bsd
+ exit ;;
+ *:IRIX*:*:*)
+ echo mips-sgi-irix`echo ${UNAME_RELEASE}|sed -e 's/-/_/g'`
+ exit ;;
+ ????????:AIX?:[12].1:2) # AIX 2.2.1 or AIX 2.1.1 is RT/PC AIX.
+ echo romp-ibm-aix # uname -m gives an 8 hex-code CPU id
+ exit ;; # Note that: echo "'`uname -s`'" gives 'AIX '
+ i*86:AIX:*:*)
+ echo i386-ibm-aix
+ exit ;;
+ ia64:AIX:*:*)
+ if [ -x /usr/bin/oslevel ] ; then
+ IBM_REV=`/usr/bin/oslevel`
+ else
+ IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE}
+ fi
+ echo ${UNAME_MACHINE}-ibm-aix${IBM_REV}
+ exit ;;
+ *:AIX:2:3)
+ if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then
+ eval $set_cc_for_build
+ sed 's/^ //' << EOF >$dummy.c
+ #include <sys/systemcfg.h>
+
+ main()
+ {
+ if (!__power_pc())
+ exit(1);
+ puts("powerpc-ibm-aix3.2.5");
+ exit(0);
+ }
+EOF
+ if $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy`
+ then
+ echo "$SYSTEM_NAME"
+ else
+ echo rs6000-ibm-aix3.2.5
+ fi
+ elif grep bos324 /usr/include/stdio.h >/dev/null 2>&1; then
+ echo rs6000-ibm-aix3.2.4
+ else
+ echo rs6000-ibm-aix3.2
+ fi
+ exit ;;
+ *:AIX:*:[4567])
+ IBM_CPU_ID=`/usr/sbin/lsdev -C -c processor -S available | sed 1q | awk '{ print $1 }'`
+ if /usr/sbin/lsattr -El ${IBM_CPU_ID} | grep ' POWER' >/dev/null 2>&1; then
+ IBM_ARCH=rs6000
+ else
+ IBM_ARCH=powerpc
+ fi
+ if [ -x /usr/bin/oslevel ] ; then
+ IBM_REV=`/usr/bin/oslevel`
+ else
+ IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE}
+ fi
+ echo ${IBM_ARCH}-ibm-aix${IBM_REV}
+ exit ;;
+ *:AIX:*:*)
+ echo rs6000-ibm-aix
+ exit ;;
+ ibmrt:4.4BSD:*|romp-ibm:BSD:*)
+ echo romp-ibm-bsd4.4
+ exit ;;
+ ibmrt:*BSD:*|romp-ibm:BSD:*) # covers RT/PC BSD and
+ echo romp-ibm-bsd${UNAME_RELEASE} # 4.3 with uname added to
+ exit ;; # report: romp-ibm BSD 4.3
+ *:BOSX:*:*)
+ echo rs6000-bull-bosx
+ exit ;;
+ DPX/2?00:B.O.S.:*:*)
+ echo m68k-bull-sysv3
+ exit ;;
+ 9000/[34]??:4.3bsd:1.*:*)
+ echo m68k-hp-bsd
+ exit ;;
+ hp300:4.4BSD:*:* | 9000/[34]??:4.3bsd:2.*:*)
+ echo m68k-hp-bsd4.4
+ exit ;;
+ 9000/[34678]??:HP-UX:*:*)
+ HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'`
+ case "${UNAME_MACHINE}" in
+ 9000/31? ) HP_ARCH=m68000 ;;
+ 9000/[34]?? ) HP_ARCH=m68k ;;
+ 9000/[678][0-9][0-9])
+ if [ -x /usr/bin/getconf ]; then
+ sc_cpu_version=`/usr/bin/getconf SC_CPU_VERSION 2>/dev/null`
+ sc_kernel_bits=`/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null`
+ case "${sc_cpu_version}" in
+ 523) HP_ARCH="hppa1.0" ;; # CPU_PA_RISC1_0
+ 528) HP_ARCH="hppa1.1" ;; # CPU_PA_RISC1_1
+ 532) # CPU_PA_RISC2_0
+ case "${sc_kernel_bits}" in
+ 32) HP_ARCH="hppa2.0n" ;;
+ 64) HP_ARCH="hppa2.0w" ;;
+ '') HP_ARCH="hppa2.0" ;; # HP-UX 10.20
+ esac ;;
+ esac
+ fi
+ if [ "${HP_ARCH}" = "" ]; then
+ eval $set_cc_for_build
+ sed 's/^ //' << EOF >$dummy.c
+
+ #define _HPUX_SOURCE
+ #include <stdlib.h>
+ #include <unistd.h>
+
+ int main ()
+ {
+ #if defined(_SC_KERNEL_BITS)
+ long bits = sysconf(_SC_KERNEL_BITS);
+ #endif
+ long cpu = sysconf (_SC_CPU_VERSION);
+
+ switch (cpu)
+ {
+ case CPU_PA_RISC1_0: puts ("hppa1.0"); break;
+ case CPU_PA_RISC1_1: puts ("hppa1.1"); break;
+ case CPU_PA_RISC2_0:
+ #if defined(_SC_KERNEL_BITS)
+ switch (bits)
+ {
+ case 64: puts ("hppa2.0w"); break;
+ case 32: puts ("hppa2.0n"); break;
+ default: puts ("hppa2.0"); break;
+ } break;
+ #else /* !defined(_SC_KERNEL_BITS) */
+ puts ("hppa2.0"); break;
+ #endif
+ default: puts ("hppa1.0"); break;
+ }
+ exit (0);
+ }
+EOF
+ (CCOPTS= $CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null) && HP_ARCH=`$dummy`
+ test -z "$HP_ARCH" && HP_ARCH=hppa
+ fi ;;
+ esac
+ if [ ${HP_ARCH} = "hppa2.0w" ]
+ then
+ eval $set_cc_for_build
+
+ # hppa2.0w-hp-hpux* has a 64-bit kernel and a compiler generating
+ # 32-bit code. hppa64-hp-hpux* has the same kernel and a compiler
+ # generating 64-bit code. GNU and HP use different nomenclature:
+ #
+ # $ CC_FOR_BUILD=cc ./config.guess
+ # => hppa2.0w-hp-hpux11.23
+ # $ CC_FOR_BUILD="cc +DA2.0w" ./config.guess
+ # => hppa64-hp-hpux11.23
+
+ if echo __LP64__ | (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) |
+ grep -q __LP64__
+ then
+ HP_ARCH="hppa2.0w"
+ else
+ HP_ARCH="hppa64"
+ fi
+ fi
+ echo ${HP_ARCH}-hp-hpux${HPUX_REV}
+ exit ;;
+ ia64:HP-UX:*:*)
+ HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'`
+ echo ia64-hp-hpux${HPUX_REV}
+ exit ;;
+ 3050*:HI-UX:*:*)
+ eval $set_cc_for_build
+ sed 's/^ //' << EOF >$dummy.c
+ #include <unistd.h>
+ int
+ main ()
+ {
+ long cpu = sysconf (_SC_CPU_VERSION);
+ /* The order matters, because CPU_IS_HP_MC68K erroneously returns
+ true for CPU_PA_RISC1_0. CPU_IS_PA_RISC returns correct
+ results, however. */
+ if (CPU_IS_PA_RISC (cpu))
+ {
+ switch (cpu)
+ {
+ case CPU_PA_RISC1_0: puts ("hppa1.0-hitachi-hiuxwe2"); break;
+ case CPU_PA_RISC1_1: puts ("hppa1.1-hitachi-hiuxwe2"); break;
+ case CPU_PA_RISC2_0: puts ("hppa2.0-hitachi-hiuxwe2"); break;
+ default: puts ("hppa-hitachi-hiuxwe2"); break;
+ }
+ }
+ else if (CPU_IS_HP_MC68K (cpu))
+ puts ("m68k-hitachi-hiuxwe2");
+ else puts ("unknown-hitachi-hiuxwe2");
+ exit (0);
+ }
+EOF
+ $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy` &&
+ { echo "$SYSTEM_NAME"; exit; }
+ echo unknown-hitachi-hiuxwe2
+ exit ;;
+ 9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:* )
+ echo hppa1.1-hp-bsd
+ exit ;;
+ 9000/8??:4.3bsd:*:*)
+ echo hppa1.0-hp-bsd
+ exit ;;
+ *9??*:MPE/iX:*:* | *3000*:MPE/iX:*:*)
+ echo hppa1.0-hp-mpeix
+ exit ;;
+ hp7??:OSF1:*:* | hp8?[79]:OSF1:*:* )
+ echo hppa1.1-hp-osf
+ exit ;;
+ hp8??:OSF1:*:*)
+ echo hppa1.0-hp-osf
+ exit ;;
+ i*86:OSF1:*:*)
+ if [ -x /usr/sbin/sysversion ] ; then
+ echo ${UNAME_MACHINE}-unknown-osf1mk
+ else
+ echo ${UNAME_MACHINE}-unknown-osf1
+ fi
+ exit ;;
+ parisc*:Lites*:*:*)
+ echo hppa1.1-hp-lites
+ exit ;;
+ C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*)
+ echo c1-convex-bsd
+ exit ;;
+ C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*)
+ if getsysinfo -f scalar_acc
+ then echo c32-convex-bsd
+ else echo c2-convex-bsd
+ fi
+ exit ;;
+ C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*)
+ echo c34-convex-bsd
+ exit ;;
+ C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*)
+ echo c38-convex-bsd
+ exit ;;
+ C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*)
+ echo c4-convex-bsd
+ exit ;;
+ CRAY*Y-MP:*:*:*)
+ echo ymp-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+ exit ;;
+ CRAY*[A-Z]90:*:*:*)
+ echo ${UNAME_MACHINE}-cray-unicos${UNAME_RELEASE} \
+ | sed -e 's/CRAY.*\([A-Z]90\)/\1/' \
+ -e y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/ \
+ -e 's/\.[^.]*$/.X/'
+ exit ;;
+ CRAY*TS:*:*:*)
+ echo t90-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+ exit ;;
+ CRAY*T3E:*:*:*)
+ echo alphaev5-cray-unicosmk${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+ exit ;;
+ CRAY*SV1:*:*:*)
+ echo sv1-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+ exit ;;
+ *:UNICOS/mp:*:*)
+ echo craynv-cray-unicosmp${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+ exit ;;
+ F30[01]:UNIX_System_V:*:* | F700:UNIX_System_V:*:*)
+ FUJITSU_PROC=`uname -m | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'`
+ FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'`
+ FUJITSU_REL=`echo ${UNAME_RELEASE} | sed -e 's/ /_/'`
+ echo "${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}"
+ exit ;;
+ 5000:UNIX_System_V:4.*:*)
+ FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'`
+ FUJITSU_REL=`echo ${UNAME_RELEASE} | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/ /_/'`
+ echo "sparc-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}"
+ exit ;;
+ i*86:BSD/386:*:* | i*86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*)
+ echo ${UNAME_MACHINE}-pc-bsdi${UNAME_RELEASE}
+ exit ;;
+ sparc*:BSD/OS:*:*)
+ echo sparc-unknown-bsdi${UNAME_RELEASE}
+ exit ;;
+ *:BSD/OS:*:*)
+ echo ${UNAME_MACHINE}-unknown-bsdi${UNAME_RELEASE}
+ exit ;;
+ *:FreeBSD:*:*)
+ UNAME_PROCESSOR=`/usr/bin/uname -p`
+ case ${UNAME_PROCESSOR} in
+ amd64)
+ echo x86_64-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;;
+ *)
+ echo ${UNAME_PROCESSOR}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;;
+ esac
+ exit ;;
+ i*:CYGWIN*:*)
+ echo ${UNAME_MACHINE}-pc-cygwin
+ exit ;;
+ *:MINGW64*:*)
+ echo ${UNAME_MACHINE}-pc-mingw64
+ exit ;;
+ *:MINGW*:*)
+ echo ${UNAME_MACHINE}-pc-mingw32
+ exit ;;
+ i*:MSYS*:*)
+ echo ${UNAME_MACHINE}-pc-msys
+ exit ;;
+ i*:windows32*:*)
+ # uname -m includes "-pc" on this system.
+ echo ${UNAME_MACHINE}-mingw32
+ exit ;;
+ i*:PW*:*)
+ echo ${UNAME_MACHINE}-pc-pw32
+ exit ;;
+ *:Interix*:*)
+ case ${UNAME_MACHINE} in
+ x86)
+ echo i586-pc-interix${UNAME_RELEASE}
+ exit ;;
+ authenticamd | genuineintel | EM64T)
+ echo x86_64-unknown-interix${UNAME_RELEASE}
+ exit ;;
+ IA64)
+ echo ia64-unknown-interix${UNAME_RELEASE}
+ exit ;;
+ esac ;;
+ [345]86:Windows_95:* | [345]86:Windows_98:* | [345]86:Windows_NT:*)
+ echo i${UNAME_MACHINE}-pc-mks
+ exit ;;
+ 8664:Windows_NT:*)
+ echo x86_64-pc-mks
+ exit ;;
+ i*:Windows_NT*:* | Pentium*:Windows_NT*:*)
+ # How do we know it's Interix rather than the generic POSIX subsystem?
+ # It also conflicts with pre-2.0 versions of AT&T UWIN. Should we
+ # UNAME_MACHINE based on the output of uname instead of i386?
+ echo i586-pc-interix
+ exit ;;
+ i*:UWIN*:*)
+ echo ${UNAME_MACHINE}-pc-uwin
+ exit ;;
+ amd64:CYGWIN*:*:* | x86_64:CYGWIN*:*:*)
+ echo x86_64-unknown-cygwin
+ exit ;;
+ p*:CYGWIN*:*)
+ echo powerpcle-unknown-cygwin
+ exit ;;
+ prep*:SunOS:5.*:*)
+ echo powerpcle-unknown-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+ exit ;;
+ *:GNU:*:*)
+ # the GNU system
+ echo `echo ${UNAME_MACHINE}|sed -e 's,[-/].*$,,'`-unknown-${LIBC}`echo ${UNAME_RELEASE}|sed -e 's,/.*$,,'`
+ exit ;;
+ *:GNU/*:*:*)
+ # other systems with GNU libc and userland
+ echo ${UNAME_MACHINE}-unknown-`echo ${UNAME_SYSTEM} | sed 's,^[^/]*/,,' | tr '[A-Z]' '[a-z]'``echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`-${LIBC}
+ exit ;;
+ i*86:Minix:*:*)
+ echo ${UNAME_MACHINE}-pc-minix
+ exit ;;
+ aarch64:Linux:*:*)
+ echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+ exit ;;
+ aarch64_be:Linux:*:*)
+ UNAME_MACHINE=aarch64_be
+ echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+ exit ;;
+ alpha:Linux:*:*)
+ case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' < /proc/cpuinfo` in
+ EV5) UNAME_MACHINE=alphaev5 ;;
+ EV56) UNAME_MACHINE=alphaev56 ;;
+ PCA56) UNAME_MACHINE=alphapca56 ;;
+ PCA57) UNAME_MACHINE=alphapca56 ;;
+ EV6) UNAME_MACHINE=alphaev6 ;;
+ EV67) UNAME_MACHINE=alphaev67 ;;
+ EV68*) UNAME_MACHINE=alphaev68 ;;
+ esac
+ objdump --private-headers /bin/sh | grep -q ld.so.1
+ if test "$?" = 0 ; then LIBC="gnulibc1" ; fi
+ echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+ exit ;;
+ arc:Linux:*:* | arceb:Linux:*:*)
+ echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+ exit ;;
+ arm*:Linux:*:*)
+ eval $set_cc_for_build
+ if echo __ARM_EABI__ | $CC_FOR_BUILD -E - 2>/dev/null \
+ | grep -q __ARM_EABI__
+ then
+ echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+ else
+ if echo __ARM_PCS_VFP | $CC_FOR_BUILD -E - 2>/dev/null \
+ | grep -q __ARM_PCS_VFP
+ then
+ echo ${UNAME_MACHINE}-unknown-linux-${LIBC}eabi
+ else
+ echo ${UNAME_MACHINE}-unknown-linux-${LIBC}eabihf
+ fi
+ fi
+ exit ;;
+ avr32*:Linux:*:*)
+ echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+ exit ;;
+ cris:Linux:*:*)
+ echo ${UNAME_MACHINE}-axis-linux-${LIBC}
+ exit ;;
+ crisv32:Linux:*:*)
+ echo ${UNAME_MACHINE}-axis-linux-${LIBC}
+ exit ;;
+ frv:Linux:*:*)
+ echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+ exit ;;
+ hexagon:Linux:*:*)
+ echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+ exit ;;
+ i*86:Linux:*:*)
+ echo ${UNAME_MACHINE}-pc-linux-${LIBC}
+ exit ;;
+ ia64:Linux:*:*)
+ echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+ exit ;;
+ m32r*:Linux:*:*)
+ echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+ exit ;;
+ m68*:Linux:*:*)
+ echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+ exit ;;
+ mips:Linux:*:* | mips64:Linux:*:*)
+ eval $set_cc_for_build
+ sed 's/^ //' << EOF >$dummy.c
+ #undef CPU
+ #undef ${UNAME_MACHINE}
+ #undef ${UNAME_MACHINE}el
+ #if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL)
+ CPU=${UNAME_MACHINE}el
+ #else
+ #if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB)
+ CPU=${UNAME_MACHINE}
+ #else
+ CPU=
+ #endif
+ #endif
+EOF
+ eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^CPU'`
+ test x"${CPU}" != x && { echo "${CPU}-unknown-linux-${LIBC}"; exit; }
+ ;;
+ or1k:Linux:*:*)
+ echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+ exit ;;
+ or32:Linux:*:*)
+ echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+ exit ;;
+ padre:Linux:*:*)
+ echo sparc-unknown-linux-${LIBC}
+ exit ;;
+ parisc64:Linux:*:* | hppa64:Linux:*:*)
+ echo hppa64-unknown-linux-${LIBC}
+ exit ;;
+ parisc:Linux:*:* | hppa:Linux:*:*)
+ # Look for CPU level
+ case `grep '^cpu[^a-z]*:' /proc/cpuinfo 2>/dev/null | cut -d' ' -f2` in
+ PA7*) echo hppa1.1-unknown-linux-${LIBC} ;;
+ PA8*) echo hppa2.0-unknown-linux-${LIBC} ;;
+ *) echo hppa-unknown-linux-${LIBC} ;;
+ esac
+ exit ;;
+ ppc64:Linux:*:*)
+ echo powerpc64-unknown-linux-${LIBC}
+ exit ;;
+ ppc:Linux:*:*)
+ echo powerpc-unknown-linux-${LIBC}
+ exit ;;
+ ppc64le:Linux:*:*)
+ echo powerpc64le-unknown-linux-${LIBC}
+ exit ;;
+ ppcle:Linux:*:*)
+ echo powerpcle-unknown-linux-${LIBC}
+ exit ;;
+ s390:Linux:*:* | s390x:Linux:*:*)
+ echo ${UNAME_MACHINE}-ibm-linux-${LIBC}
+ exit ;;
+ sh64*:Linux:*:*)
+ echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+ exit ;;
+ sh*:Linux:*:*)
+ echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+ exit ;;
+ sparc:Linux:*:* | sparc64:Linux:*:*)
+ echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+ exit ;;
+ tile*:Linux:*:*)
+ echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+ exit ;;
+ vax:Linux:*:*)
+ echo ${UNAME_MACHINE}-dec-linux-${LIBC}
+ exit ;;
+ x86_64:Linux:*:*)
+ echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+ exit ;;
+ xtensa*:Linux:*:*)
+ echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+ exit ;;
+ i*86:DYNIX/ptx:4*:*)
+ # ptx 4.0 does uname -s correctly, with DYNIX/ptx in there.
+ # earlier versions are messed up and put the nodename in both
+ # sysname and nodename.
+ echo i386-sequent-sysv4
+ exit ;;
+ i*86:UNIX_SV:4.2MP:2.*)
+ # Unixware is an offshoot of SVR4, but it has its own version
+ # number series starting with 2...
+ # I am not positive that other SVR4 systems won't match this,
+ # I just have to hope. -- rms.
+ # Use sysv4.2uw... so that sysv4* matches it.
+ echo ${UNAME_MACHINE}-pc-sysv4.2uw${UNAME_VERSION}
+ exit ;;
+ i*86:OS/2:*:*)
+ # If we were able to find `uname', then EMX Unix compatibility
+ # is probably installed.
+ echo ${UNAME_MACHINE}-pc-os2-emx
+ exit ;;
+ i*86:XTS-300:*:STOP)
+ echo ${UNAME_MACHINE}-unknown-stop
+ exit ;;
+ i*86:atheos:*:*)
+ echo ${UNAME_MACHINE}-unknown-atheos
+ exit ;;
+ i*86:syllable:*:*)
+ echo ${UNAME_MACHINE}-pc-syllable
+ exit ;;
+ i*86:LynxOS:2.*:* | i*86:LynxOS:3.[01]*:* | i*86:LynxOS:4.[02]*:*)
+ echo i386-unknown-lynxos${UNAME_RELEASE}
+ exit ;;
+ i*86:*DOS:*:*)
+ echo ${UNAME_MACHINE}-pc-msdosdjgpp
+ exit ;;
+ i*86:*:4.*:* | i*86:SYSTEM_V:4.*:*)
+ UNAME_REL=`echo ${UNAME_RELEASE} | sed 's/\/MP$//'`
+ if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then
+ echo ${UNAME_MACHINE}-univel-sysv${UNAME_REL}
+ else
+ echo ${UNAME_MACHINE}-pc-sysv${UNAME_REL}
+ fi
+ exit ;;
+ i*86:*:5:[678]*)
+ # UnixWare 7.x, OpenUNIX and OpenServer 6.
+ case `/bin/uname -X | grep "^Machine"` in
+ *486*) UNAME_MACHINE=i486 ;;
+ *Pentium) UNAME_MACHINE=i586 ;;
+ *Pent*|*Celeron) UNAME_MACHINE=i686 ;;
+ esac
+ echo ${UNAME_MACHINE}-unknown-sysv${UNAME_RELEASE}${UNAME_SYSTEM}${UNAME_VERSION}
+ exit ;;
+ i*86:*:3.2:*)
+ if test -f /usr/options/cb.name; then
+ UNAME_REL=`sed -n 's/.*Version //p' </usr/options/cb.name`
+ echo ${UNAME_MACHINE}-pc-isc$UNAME_REL
+ elif /bin/uname -X 2>/dev/null >/dev/null ; then
+ UNAME_REL=`(/bin/uname -X|grep Release|sed -e 's/.*= //')`
+ (/bin/uname -X|grep i80486 >/dev/null) && UNAME_MACHINE=i486
+ (/bin/uname -X|grep '^Machine.*Pentium' >/dev/null) \
+ && UNAME_MACHINE=i586
+ (/bin/uname -X|grep '^Machine.*Pent *II' >/dev/null) \
+ && UNAME_MACHINE=i686
+ (/bin/uname -X|grep '^Machine.*Pentium Pro' >/dev/null) \
+ && UNAME_MACHINE=i686
+ echo ${UNAME_MACHINE}-pc-sco$UNAME_REL
+ else
+ echo ${UNAME_MACHINE}-pc-sysv32
+ fi
+ exit ;;
+ pc:*:*:*)
+ # Left here for compatibility:
+ # uname -m prints for DJGPP always 'pc', but it prints nothing about
+ # the processor, so we play safe by assuming i586.
+ # Note: whatever this is, it MUST be the same as what config.sub
+ # prints for the "djgpp" host, or else GDB configury will decide that
+ # this is a cross-build.
+ echo i586-pc-msdosdjgpp
+ exit ;;
+ Intel:Mach:3*:*)
+ echo i386-pc-mach3
+ exit ;;
+ paragon:*:*:*)
+ echo i860-intel-osf1
+ exit ;;
+ i860:*:4.*:*) # i860-SVR4
+ if grep Stardent /usr/include/sys/uadmin.h >/dev/null 2>&1 ; then
+ echo i860-stardent-sysv${UNAME_RELEASE} # Stardent Vistra i860-SVR4
+ else # Add other i860-SVR4 vendors below as they are discovered.
+ echo i860-unknown-sysv${UNAME_RELEASE} # Unknown i860-SVR4
+ fi
+ exit ;;
+ mini*:CTIX:SYS*5:*)
+ # "miniframe"
+ echo m68010-convergent-sysv
+ exit ;;
+ mc68k:UNIX:SYSTEM5:3.51m)
+ echo m68k-convergent-sysv
+ exit ;;
+ M680?0:D-NIX:5.3:*)
+ echo m68k-diab-dnix
+ exit ;;
+ M68*:*:R3V[5678]*:*)
+ test -r /sysV68 && { echo 'm68k-motorola-sysv'; exit; } ;;
+ 3[345]??:*:4.0:3.0 | 3[34]??A:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 3[34]??/*:*:4.0:3.0 | 4400:*:4.0:3.0 | 4850:*:4.0:3.0 | SKA40:*:4.0:3.0 | SDS2:*:4.0:3.0 | SHG2:*:4.0:3.0 | S7501*:*:4.0:3.0)
+ OS_REL=''
+ test -r /etc/.relid \
+ && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid`
+ /bin/uname -p 2>/dev/null | grep 86 >/dev/null \
+ && { echo i486-ncr-sysv4.3${OS_REL}; exit; }
+ /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \
+ && { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;;
+ 3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*)
+ /bin/uname -p 2>/dev/null | grep 86 >/dev/null \
+ && { echo i486-ncr-sysv4; exit; } ;;
+ NCR*:*:4.2:* | MPRAS*:*:4.2:*)
+ OS_REL='.3'
+ test -r /etc/.relid \
+ && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid`
+ /bin/uname -p 2>/dev/null | grep 86 >/dev/null \
+ && { echo i486-ncr-sysv4.3${OS_REL}; exit; }
+ /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \
+ && { echo i586-ncr-sysv4.3${OS_REL}; exit; }
+ /bin/uname -p 2>/dev/null | /bin/grep pteron >/dev/null \
+ && { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;;
+ m68*:LynxOS:2.*:* | m68*:LynxOS:3.0*:*)
+ echo m68k-unknown-lynxos${UNAME_RELEASE}
+ exit ;;
+ mc68030:UNIX_System_V:4.*:*)
+ echo m68k-atari-sysv4
+ exit ;;
+ TSUNAMI:LynxOS:2.*:*)
+ echo sparc-unknown-lynxos${UNAME_RELEASE}
+ exit ;;
+ rs6000:LynxOS:2.*:*)
+ echo rs6000-unknown-lynxos${UNAME_RELEASE}
+ exit ;;
+ PowerPC:LynxOS:2.*:* | PowerPC:LynxOS:3.[01]*:* | PowerPC:LynxOS:4.[02]*:*)
+ echo powerpc-unknown-lynxos${UNAME_RELEASE}
+ exit ;;
+ SM[BE]S:UNIX_SV:*:*)
+ echo mips-dde-sysv${UNAME_RELEASE}
+ exit ;;
+ RM*:ReliantUNIX-*:*:*)
+ echo mips-sni-sysv4
+ exit ;;
+ RM*:SINIX-*:*:*)
+ echo mips-sni-sysv4
+ exit ;;
+ *:SINIX-*:*:*)
+ if uname -p 2>/dev/null >/dev/null ; then
+ UNAME_MACHINE=`(uname -p) 2>/dev/null`
+ echo ${UNAME_MACHINE}-sni-sysv4
+ else
+ echo ns32k-sni-sysv
+ fi
+ exit ;;
+ PENTIUM:*:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort
+ # says <Richard.M.Bartel@ccMail.Census.GOV>
+ echo i586-unisys-sysv4
+ exit ;;
+ *:UNIX_System_V:4*:FTX*)
+ # From Gerald Hewes <hewes@openmarket.com>.
+ # How about differentiating between stratus architectures? -djm
+ echo hppa1.1-stratus-sysv4
+ exit ;;
+ *:*:*:FTX*)
+ # From seanf@swdc.stratus.com.
+ echo i860-stratus-sysv4
+ exit ;;
+ i*86:VOS:*:*)
+ # From Paul.Green@stratus.com.
+ echo ${UNAME_MACHINE}-stratus-vos
+ exit ;;
+ *:VOS:*:*)
+ # From Paul.Green@stratus.com.
+ echo hppa1.1-stratus-vos
+ exit ;;
+ mc68*:A/UX:*:*)
+ echo m68k-apple-aux${UNAME_RELEASE}
+ exit ;;
+ news*:NEWS-OS:6*:*)
+ echo mips-sony-newsos6
+ exit ;;
+ R[34]000:*System_V*:*:* | R4000:UNIX_SYSV:*:* | R*000:UNIX_SV:*:*)
+ if [ -d /usr/nec ]; then
+ echo mips-nec-sysv${UNAME_RELEASE}
+ else
+ echo mips-unknown-sysv${UNAME_RELEASE}
+ fi
+ exit ;;
+ BeBox:BeOS:*:*) # BeOS running on hardware made by Be, PPC only.
+ echo powerpc-be-beos
+ exit ;;
+ BeMac:BeOS:*:*) # BeOS running on Mac or Mac clone, PPC only.
+ echo powerpc-apple-beos
+ exit ;;
+ BePC:BeOS:*:*) # BeOS running on Intel PC compatible.
+ echo i586-pc-beos
+ exit ;;
+ BePC:Haiku:*:*) # Haiku running on Intel PC compatible.
+ echo i586-pc-haiku
+ exit ;;
+ x86_64:Haiku:*:*)
+ echo x86_64-unknown-haiku
+ exit ;;
+ SX-4:SUPER-UX:*:*)
+ echo sx4-nec-superux${UNAME_RELEASE}
+ exit ;;
+ SX-5:SUPER-UX:*:*)
+ echo sx5-nec-superux${UNAME_RELEASE}
+ exit ;;
+ SX-6:SUPER-UX:*:*)
+ echo sx6-nec-superux${UNAME_RELEASE}
+ exit ;;
+ SX-7:SUPER-UX:*:*)
+ echo sx7-nec-superux${UNAME_RELEASE}
+ exit ;;
+ SX-8:SUPER-UX:*:*)
+ echo sx8-nec-superux${UNAME_RELEASE}
+ exit ;;
+ SX-8R:SUPER-UX:*:*)
+ echo sx8r-nec-superux${UNAME_RELEASE}
+ exit ;;
+ Power*:Rhapsody:*:*)
+ echo powerpc-apple-rhapsody${UNAME_RELEASE}
+ exit ;;
+ *:Rhapsody:*:*)
+ echo ${UNAME_MACHINE}-apple-rhapsody${UNAME_RELEASE}
+ exit ;;
+ *:Darwin:*:*)
+ UNAME_PROCESSOR=`uname -p` || UNAME_PROCESSOR=unknown
+ eval $set_cc_for_build
+ if test "$UNAME_PROCESSOR" = unknown ; then
+ UNAME_PROCESSOR=powerpc
+ fi
+ if test `echo "$UNAME_RELEASE" | sed -e 's/\..*//'` -le 10 ; then
+ if [ "$CC_FOR_BUILD" != 'no_compiler_found' ]; then
+ if (echo '#ifdef __LP64__'; echo IS_64BIT_ARCH; echo '#endif') | \
+ (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | \
+ grep IS_64BIT_ARCH >/dev/null
+ then
+ case $UNAME_PROCESSOR in
+ i386) UNAME_PROCESSOR=x86_64 ;;
+ powerpc) UNAME_PROCESSOR=powerpc64 ;;
+ esac
+ fi
+ fi
+ elif test "$UNAME_PROCESSOR" = i386 ; then
+ # Avoid executing cc on OS X 10.9, as it ships with a stub
+ # that puts up a graphical alert prompting to install
+ # developer tools. Any system running Mac OS X 10.7 or
+ # later (Darwin 11 and later) is required to have a 64-bit
+ # processor. This is not true of the ARM version of Darwin
+ # that Apple uses in portable devices.
+ UNAME_PROCESSOR=x86_64
+ fi
+ echo ${UNAME_PROCESSOR}-apple-darwin${UNAME_RELEASE}
+ exit ;;
+ *:procnto*:*:* | *:QNX:[0123456789]*:*)
+ UNAME_PROCESSOR=`uname -p`
+ if test "$UNAME_PROCESSOR" = "x86"; then
+ UNAME_PROCESSOR=i386
+ UNAME_MACHINE=pc
+ fi
+ echo ${UNAME_PROCESSOR}-${UNAME_MACHINE}-nto-qnx${UNAME_RELEASE}
+ exit ;;
+ *:QNX:*:4*)
+ echo i386-pc-qnx
+ exit ;;
+ NEO-?:NONSTOP_KERNEL:*:*)
+ echo neo-tandem-nsk${UNAME_RELEASE}
+ exit ;;
+ NSE-*:NONSTOP_KERNEL:*:*)
+ echo nse-tandem-nsk${UNAME_RELEASE}
+ exit ;;
+ NSR-?:NONSTOP_KERNEL:*:*)
+ echo nsr-tandem-nsk${UNAME_RELEASE}
+ exit ;;
+ *:NonStop-UX:*:*)
+ echo mips-compaq-nonstopux
+ exit ;;
+ BS2000:POSIX*:*:*)
+ echo bs2000-siemens-sysv
+ exit ;;
+ DS/*:UNIX_System_V:*:*)
+ echo ${UNAME_MACHINE}-${UNAME_SYSTEM}-${UNAME_RELEASE}
+ exit ;;
+ *:Plan9:*:*)
+ # "uname -m" is not consistent, so use $cputype instead. 386
+ # is converted to i386 for consistency with other x86
+ # operating systems.
+ if test "$cputype" = "386"; then
+ UNAME_MACHINE=i386
+ else
+ UNAME_MACHINE="$cputype"
+ fi
+ echo ${UNAME_MACHINE}-unknown-plan9
+ exit ;;
+ *:TOPS-10:*:*)
+ echo pdp10-unknown-tops10
+ exit ;;
+ *:TENEX:*:*)
+ echo pdp10-unknown-tenex
+ exit ;;
+ KS10:TOPS-20:*:* | KL10:TOPS-20:*:* | TYPE4:TOPS-20:*:*)
+ echo pdp10-dec-tops20
+ exit ;;
+ XKL-1:TOPS-20:*:* | TYPE5:TOPS-20:*:*)
+ echo pdp10-xkl-tops20
+ exit ;;
+ *:TOPS-20:*:*)
+ echo pdp10-unknown-tops20
+ exit ;;
+ *:ITS:*:*)
+ echo pdp10-unknown-its
+ exit ;;
+ SEI:*:*:SEIUX)
+ echo mips-sei-seiux${UNAME_RELEASE}
+ exit ;;
+ *:DragonFly:*:*)
+ echo ${UNAME_MACHINE}-unknown-dragonfly`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`
+ exit ;;
+ *:*VMS:*:*)
+ UNAME_MACHINE=`(uname -p) 2>/dev/null`
+ case "${UNAME_MACHINE}" in
+ A*) echo alpha-dec-vms ; exit ;;
+ I*) echo ia64-dec-vms ; exit ;;
+ V*) echo vax-dec-vms ; exit ;;
+ esac ;;
+ *:XENIX:*:SysV)
+ echo i386-pc-xenix
+ exit ;;
+ i*86:skyos:*:*)
+ echo ${UNAME_MACHINE}-pc-skyos`echo ${UNAME_RELEASE}` | sed -e 's/ .*$//'
+ exit ;;
+ i*86:rdos:*:*)
+ echo ${UNAME_MACHINE}-pc-rdos
+ exit ;;
+ i*86:AROS:*:*)
+ echo ${UNAME_MACHINE}-pc-aros
+ exit ;;
+ x86_64:VMkernel:*:*)
+ echo ${UNAME_MACHINE}-unknown-esx<