Import Cobalt 10.56829
diff --git a/src/cobalt/accessibility/screen_reader.cc b/src/cobalt/accessibility/screen_reader.cc
index 54a8d8c..9faee21 100644
--- a/src/cobalt/accessibility/screen_reader.cc
+++ b/src/cobalt/accessibility/screen_reader.cc
@@ -34,7 +34,8 @@
ScreenReader::ScreenReader(dom::Document* document, TTSEngine* tts_engine,
dom::MutationObserverTaskManager* task_manager)
- : enabled_(true), document_(document), tts_engine_(tts_engine) {
+ : enabled_(true), document_(document), tts_engine_(tts_engine),
+ focus_changed_(false) {
document_->AddObserver(this);
live_region_observer_ = new dom::MutationObserver(
base::Bind(&ScreenReader::MutationObserverCallback,
@@ -64,6 +65,17 @@
}
void ScreenReader::OnFocusChanged() {
+ if (focus_changed_) {
+ return;
+ }
+ focus_changed_ = true;
+ MessageLoop::current()->PostTask(
+ FROM_HERE,
+ base::Bind(&ScreenReader::FocusChangedCallback, base::Unretained(this)));
+}
+
+void ScreenReader::FocusChangedCallback() {
+ focus_changed_ = false;
if (!enabled_) {
return;
}
@@ -74,7 +86,7 @@
}
}
-// MutationObserver callback for tracking the creationg and destruction of
+// MutationObserver callback for tracking the creation and destruction of
// live regions.
void ScreenReader::MutationObserverCallback(
const MutationRecordSequence& sequence,
diff --git a/src/cobalt/accessibility/screen_reader.h b/src/cobalt/accessibility/screen_reader.h
index 846d50f..542ed22 100644
--- a/src/cobalt/accessibility/screen_reader.h
+++ b/src/cobalt/accessibility/screen_reader.h
@@ -47,6 +47,7 @@
private:
typedef script::Sequence<scoped_refptr<dom::MutationRecord> >
MutationRecordSequence;
+ void FocusChangedCallback();
// MutationObserver callback for tracking live regions.
void MutationObserverCallback(
const MutationRecordSequence& sequence,
@@ -56,6 +57,7 @@
dom::Document* document_;
TTSEngine* tts_engine_;
scoped_refptr<dom::MutationObserver> live_region_observer_;
+ bool focus_changed_;
friend class scoped_ptr<ScreenReader>;
DISALLOW_COPY_AND_ASSIGN(ScreenReader);
diff --git a/src/cobalt/base/tokens.h b/src/cobalt/base/tokens.h
index 7ca128e..8929dd1 100644
--- a/src/cobalt/base/tokens.h
+++ b/src/cobalt/base/tokens.h
@@ -57,6 +57,8 @@
MacroOpWithNameOnly(ended) \
MacroOpWithNameOnly(error) \
MacroOpWithNameOnly(focus) \
+ MacroOpWithNameOnly(focusin) \
+ MacroOpWithNameOnly(focusout) \
MacroOpWithNameOnly(hashchange) \
MacroOpWithNameOnly(keydown) \
MacroOpWithNameOnly(keypress) \
diff --git a/src/cobalt/bindings/IDLExtendedAttributes.txt b/src/cobalt/bindings/IDLExtendedAttributes.txt
index 8b1c115..bd7bd59 100644
--- a/src/cobalt/bindings/IDLExtendedAttributes.txt
+++ b/src/cobalt/bindings/IDLExtendedAttributes.txt
@@ -57,20 +57,6 @@
# http://heycam.github.io/webidl/#Exposed
Exposed=*
-# The value of this attribute is a list of functions to be called that will
-# return a scoped_refptr<Wrappable>.
-# The raw pointer will be added as an opaque root when an instance of this
-# interface is visited during garbage collection.
-AddOpaqueRoots=|*
-
-# The value of this attribute is a function to be called that will return a
-# scoped_refptr<Wrappable> that represents an opaque root of an object
-# implementing this interface.
-# If opaque root of an object is in the set of opaque roots that have been
-# collected during garbage collection, the object's wrapper will be kept alive
-# as well.
-GetOpaqueRoot=*
-
# Call the Cobalt function this property is bound to with the corresponding
# object added to the head of the function's parameters.
# StackTrace is a custom addition to CallWith for the purpose of testing
diff --git a/src/cobalt/bindings/code_generator_cobalt.py b/src/cobalt/bindings/code_generator_cobalt.py
index f3a7892..043bad1 100644
--- a/src/cobalt/bindings/code_generator_cobalt.py
+++ b/src/cobalt/bindings/code_generator_cobalt.py
@@ -431,11 +431,15 @@
referenced_interface_names = set(
get_interface_type_names_from_typed_objects(self.info_provider,
dictionary.members))
+ if dictionary.parent:
+ referenced_interface_names.add(dictionary.parent)
+ context['parent'] = dictionary.parent
+
referenced_class_contexts = self.referenced_class_contexts(
referenced_interface_names, for_conversion)
- context['includes'] = sorted((interface['include']
- for interface in referenced_class_contexts))
+ context['includes'] = sorted(interface['include']
+ for interface in referenced_class_contexts)
context['forward_declarations'] = sorted(
referenced_class_contexts, key=lambda x: x['fully_qualified_name'])
context['components'] = self.path_builder.NamespaceComponents(
@@ -467,10 +471,6 @@
'NoInterfaceObject' not in interface.extended_attributes),
'conditional':
interface.extended_attributes.get('Conditional', None),
- 'add_opaque_roots':
- interface.extended_attributes.get('AddOpaqueRoots', None),
- 'get_opaque_root':
- interface.extended_attributes.get('GetOpaqueRoot', None),
}
interfaces_info = self.info_provider.interfaces_info
if is_global_interface(interface):
diff --git a/src/cobalt/bindings/generated/mozjs/testing/cobalt/bindings/testing/mozjs_garbage_collection_test_interface.cc b/src/cobalt/bindings/generated/mozjs/testing/cobalt/bindings/testing/mozjs_garbage_collection_test_interface.cc
index e496560..eb0a945 100644
--- a/src/cobalt/bindings/generated/mozjs/testing/cobalt/bindings/testing/mozjs_garbage_collection_test_interface.cc
+++ b/src/cobalt/bindings/generated/mozjs/testing/cobalt/bindings/testing/mozjs_garbage_collection_test_interface.cc
@@ -93,13 +93,6 @@
namespace {
-Wrappable* GetOpaqueRootFromWrappable(
- const scoped_refptr<Wrappable>& wrappable) {
- GarbageCollectionTestInterface* impl =
- base::polymorphic_downcast<GarbageCollectionTestInterface*>(wrappable.get());
- return impl->GetHead();
-}
-
class MozjsGarbageCollectionTestInterfaceHandler : public ProxyHandler {
public:
MozjsGarbageCollectionTestInterfaceHandler()
@@ -511,11 +504,7 @@
JS::RootedObject proxy(context,
ProxyHandler::NewProxy(context, new_object, prototype, NULL,
proxy_handler.Pointer()));
- WrapperPrivate::GetOpaqueRootFunction get_root;
- WrapperPrivate::GetReachableWrappablesFunction get_reachable_wrappables;
- get_root = base::Bind(&GetOpaqueRootFromWrappable);
- WrapperPrivate::AddPrivateData(
- context, proxy, wrappable, get_root, get_reachable_wrappables);
+ WrapperPrivate::AddPrivateData(context, proxy, wrappable);
return proxy;
}
diff --git a/src/cobalt/bindings/generated/mozjs/testing/cobalt/bindings/testing/mozjs_get_opaque_root_interface.cc b/src/cobalt/bindings/generated/mozjs/testing/cobalt/bindings/testing/mozjs_get_opaque_root_interface.cc
deleted file mode 100644
index 0ef8902..0000000
--- a/src/cobalt/bindings/generated/mozjs/testing/cobalt/bindings/testing/mozjs_get_opaque_root_interface.cc
+++ /dev/null
@@ -1,417 +0,0 @@
-// Copyright 2017 Google Inc. All Rights Reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-// clang-format off
-
-// This file has been auto-generated by bindings/code_generator_cobalt.py. DO NOT MODIFY!
-// Auto-generated from template: bindings/mozjs/templates/interface.cc.template
-
-#include "cobalt/bindings/testing/mozjs_get_opaque_root_interface.h"
-
-#include "base/debug/trace_event.h"
-#include "cobalt/base/polymorphic_downcast.h"
-#include "cobalt/script/global_environment.h"
-#include "cobalt/script/opaque_handle.h"
-#include "cobalt/script/script_value.h"
-
-#include "mozjs_gen_type_conversion.h"
-
-#include "base/lazy_instance.h"
-#include "cobalt/script/exception_state.h"
-#include "cobalt/script/mozjs/callback_function_conversion.h"
-#include "cobalt/script/mozjs/conversion_helpers.h"
-#include "cobalt/script/mozjs/mozjs_callback_function.h"
-#include "cobalt/script/mozjs/mozjs_exception_state.h"
-#include "cobalt/script/mozjs/mozjs_global_environment.h"
-#include "cobalt/script/mozjs/mozjs_object_handle.h"
-#include "cobalt/script/mozjs/mozjs_property_enumerator.h"
-#include "cobalt/script/mozjs/mozjs_user_object_holder.h"
-#include "cobalt/script/mozjs/mozjs_value_handle.h"
-#include "cobalt/script/mozjs/native_promise.h"
-#include "cobalt/script/mozjs/proxy_handler.h"
-#include "cobalt/script/mozjs/type_traits.h"
-#include "cobalt/script/mozjs/wrapper_factory.h"
-#include "cobalt/script/mozjs/wrapper_private.h"
-#include "cobalt/script/property_enumerator.h"
-#include "cobalt/script/sequence.h"
-#include "third_party/mozjs/js/src/jsapi.h"
-#include "third_party/mozjs/js/src/jsfriendapi.h"
-
-namespace {
-using cobalt::bindings::testing::GetOpaqueRootInterface;
-using cobalt::bindings::testing::MozjsGetOpaqueRootInterface;
-using cobalt::script::CallbackInterfaceTraits;
-using cobalt::script::GlobalEnvironment;
-using cobalt::script::OpaqueHandle;
-using cobalt::script::OpaqueHandleHolder;
-using cobalt::script::ScriptValue;
-using cobalt::script::ValueHandle;
-using cobalt::script::Wrappable;
-
-using cobalt::script::CallbackFunction;
-using cobalt::script::CallbackInterfaceTraits;
-using cobalt::script::ExceptionState;
-using cobalt::script::Wrappable;
-using cobalt::script::mozjs::FromJSValue;
-using cobalt::script::mozjs::InterfaceData;
-using cobalt::script::mozjs::MozjsCallbackFunction;
-using cobalt::script::mozjs::MozjsExceptionState;
-using cobalt::script::mozjs::MozjsGlobalEnvironment;
-using cobalt::script::mozjs::MozjsPropertyEnumerator;
-using cobalt::script::mozjs::MozjsUserObjectHolder;
-using cobalt::script::mozjs::ProxyHandler;
-using cobalt::script::mozjs::ToJSValue;
-using cobalt::script::mozjs::TypeTraits;
-using cobalt::script::mozjs::WrapperFactory;
-using cobalt::script::mozjs::WrapperPrivate;
-using cobalt::script::mozjs::kConversionFlagClamped;
-using cobalt::script::mozjs::kConversionFlagNullable;
-using cobalt::script::mozjs::kConversionFlagRestricted;
-using cobalt::script::mozjs::kConversionFlagTreatNullAsEmptyString;
-using cobalt::script::mozjs::kConversionFlagTreatUndefinedAsEmptyString;
-using cobalt::script::mozjs::kNoConversionFlags;
-} // namespace
-
-namespace cobalt {
-namespace bindings {
-namespace testing {
-
-namespace {
-
-Wrappable* GetOpaqueRootFromWrappable(
- const scoped_refptr<Wrappable>& wrappable) {
- GetOpaqueRootInterface* impl =
- base::polymorphic_downcast<GetOpaqueRootInterface*>(wrappable.get());
- return impl->get_opaque_root_function_name();
-}
-
-void GetReachableWrappables(const scoped_refptr<Wrappable>& wrappable,
- WrapperPrivate::WrappableVector* reachable) {
- DCHECK(reachable);
- GetOpaqueRootInterface* impl =
- base::polymorphic_downcast<GetOpaqueRootInterface*>(wrappable.get());
- Wrappable* reachable_0 = impl->add_opaque_root_function_name();
- if (reachable_0) {
- reachable->push_back(reachable_0);
- }
-}
-
-class MozjsGetOpaqueRootInterfaceHandler : public ProxyHandler {
- public:
- MozjsGetOpaqueRootInterfaceHandler()
- : ProxyHandler(indexed_property_hooks, named_property_hooks) {}
-
- private:
- static NamedPropertyHooks named_property_hooks;
- static IndexedPropertyHooks indexed_property_hooks;
-};
-
-ProxyHandler::NamedPropertyHooks
-MozjsGetOpaqueRootInterfaceHandler::named_property_hooks = {
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
-};
-ProxyHandler::IndexedPropertyHooks
-MozjsGetOpaqueRootInterfaceHandler::indexed_property_hooks = {
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
-};
-
-static base::LazyInstance<MozjsGetOpaqueRootInterfaceHandler>
- proxy_handler;
-
-JSBool Constructor(JSContext* context, unsigned int argc, JS::Value* vp);
-JSBool HasInstance(JSContext *context, JS::HandleObject type,
- JS::MutableHandleValue vp, JSBool *success) {
- JS::RootedObject global_object(
- context, JS_GetGlobalForObject(context, type));
- DCHECK(global_object);
-
- JS::RootedObject prototype(
- context, MozjsGetOpaqueRootInterface::GetPrototype(context, global_object));
-
- // |IsDelegate| walks the prototype chain of an object returning true if
- // .prototype is found.
- bool is_delegate;
- if (!IsDelegate(context, prototype, vp, &is_delegate)) {
- *success = false;
- return false;
- }
-
- *success = is_delegate;
- return true;
-}
-
-InterfaceData* CreateCachedInterfaceData() {
- InterfaceData* interface_data = new InterfaceData();
- memset(&interface_data->instance_class_definition, 0,
- sizeof(interface_data->instance_class_definition));
- memset(&interface_data->prototype_class_definition, 0,
- sizeof(interface_data->prototype_class_definition));
- memset(&interface_data->interface_object_class_definition, 0,
- sizeof(interface_data->interface_object_class_definition));
-
- JSClass* instance_class = &interface_data->instance_class_definition;
- const int kGlobalFlags = 0;
- instance_class->name = "GetOpaqueRootInterface";
- instance_class->flags = kGlobalFlags | JSCLASS_HAS_PRIVATE;
- instance_class->addProperty = JS_PropertyStub;
- instance_class->delProperty = JS_DeletePropertyStub;
- instance_class->getProperty = JS_PropertyStub;
- instance_class->setProperty = JS_StrictPropertyStub;
- instance_class->enumerate = JS_EnumerateStub;
- instance_class->resolve = JS_ResolveStub;
- instance_class->convert = JS_ConvertStub;
- // Function to be called before on object of this class is garbage collected.
- instance_class->finalize = &WrapperPrivate::Finalizer;
- // Called to trace objects that can be referenced from this object.
- instance_class->trace = &WrapperPrivate::Trace;
-
- JSClass* prototype_class = &interface_data->prototype_class_definition;
- prototype_class->name = "GetOpaqueRootInterfacePrototype";
- prototype_class->flags = 0;
- prototype_class->addProperty = JS_PropertyStub;
- prototype_class->delProperty = JS_DeletePropertyStub;
- prototype_class->getProperty = JS_PropertyStub;
- prototype_class->setProperty = JS_StrictPropertyStub;
- prototype_class->enumerate = JS_EnumerateStub;
- prototype_class->resolve = JS_ResolveStub;
- prototype_class->convert = JS_ConvertStub;
-
- JSClass* interface_object_class =
- &interface_data->interface_object_class_definition;
- interface_object_class->name = "GetOpaqueRootInterfaceConstructor";
- interface_object_class->flags = 0;
- interface_object_class->addProperty = JS_PropertyStub;
- interface_object_class->delProperty = JS_DeletePropertyStub;
- interface_object_class->getProperty = JS_PropertyStub;
- interface_object_class->setProperty = JS_StrictPropertyStub;
- interface_object_class->enumerate = JS_EnumerateStub;
- interface_object_class->resolve = JS_ResolveStub;
- interface_object_class->convert = JS_ConvertStub;
- interface_object_class->hasInstance = &HasInstance;
- interface_object_class->construct = Constructor;
- return interface_data;
-}
-
-
-const JSPropertySpec prototype_properties[] = {
- JS_PS_END
-};
-
-const JSFunctionSpec prototype_functions[] = {
- JS_FS_END
-};
-
-const JSPropertySpec interface_object_properties[] = {
- JS_PS_END
-};
-
-const JSFunctionSpec interface_object_functions[] = {
- JS_FS_END
-};
-
-const JSPropertySpec own_properties[] = {
- JS_PS_END
-};
-
-void InitializePrototypeAndInterfaceObject(
- InterfaceData* interface_data, JSContext* context,
- JS::HandleObject global_object) {
- DCHECK(!interface_data->prototype);
- DCHECK(!interface_data->interface_object);
- DCHECK(JS_IsGlobalObject(global_object));
-
- JS::RootedObject parent_prototype(
- context, JS_GetObjectPrototype(context, global_object));
- DCHECK(parent_prototype);
-
- // Create the Prototype object.
- interface_data->prototype = JS_NewObjectWithGivenProto(
- context, &interface_data->prototype_class_definition, parent_prototype,
- NULL);
- bool success = JS_DefineProperties(
- context, interface_data->prototype, prototype_properties);
- DCHECK(success);
- success = JS_DefineFunctions(
- context, interface_data->prototype, prototype_functions);
- DCHECK(success);
-
- JS::RootedObject function_prototype(
- context, JS_GetFunctionPrototype(context, global_object));
- DCHECK(function_prototype);
- // Create the Interface object.
- interface_data->interface_object = JS_NewObjectWithGivenProto(
- context, &interface_data->interface_object_class_definition,
- function_prototype, NULL);
-
- // Add the InterfaceObject.name property.
- JS::RootedObject rooted_interface_object(
- context, interface_data->interface_object);
- JS::RootedValue name_value(context);
- const char name[] =
- "GetOpaqueRootInterface";
- name_value.setString(JS_NewStringCopyZ(context, name));
- success =
- JS_DefineProperty(context, rooted_interface_object, "name", name_value,
- JS_PropertyStub, JS_StrictPropertyStub,
- JSPROP_READONLY);
- DCHECK(success);
-
- // Add the InterfaceObject.length property. It is set to the length of the
- // shortest argument list of all overload constructors.
- JS::RootedValue length_value(context);
- length_value.setInt32(0);
- success =
- JS_DefineProperty(context, rooted_interface_object, "length",
- length_value, JS_PropertyStub, JS_StrictPropertyStub,
- JSPROP_READONLY);
- DCHECK(success);
-
- // Define interface object properties (including constants).
- success = JS_DefineProperties(context, rooted_interface_object,
- interface_object_properties);
- DCHECK(success);
- // Define interface object functions (static).
- success = JS_DefineFunctions(context, rooted_interface_object,
- interface_object_functions);
- DCHECK(success);
-
-
- // Set the Prototype.constructor and Constructor.prototype properties.
- DCHECK(interface_data->interface_object);
- DCHECK(interface_data->prototype);
- JS::RootedObject rooted_prototype(context, interface_data->prototype);
- success = JS_LinkConstructorAndPrototype(
- context,
- rooted_interface_object,
- rooted_prototype);
- DCHECK(success);
-}
-
-InterfaceData* GetInterfaceData(JSContext* context) {
- MozjsGlobalEnvironment* global_environment =
- static_cast<MozjsGlobalEnvironment*>(JS_GetContextPrivate(context));
- // Use the address of the properties definition for this interface as a
- // unique key for looking up the InterfaceData for this interface.
- intptr_t key = reinterpret_cast<intptr_t>(&own_properties);
- InterfaceData* interface_data = global_environment->GetInterfaceData(key);
- if (!interface_data) {
- interface_data = CreateCachedInterfaceData();
- DCHECK(interface_data);
- global_environment->CacheInterfaceData(key, interface_data);
- DCHECK_EQ(interface_data, global_environment->GetInterfaceData(key));
- }
- return interface_data;
-}
-
-} // namespace
-
-// static
-JSObject* MozjsGetOpaqueRootInterface::CreateProxy(
- JSContext* context, const scoped_refptr<Wrappable>& wrappable) {
- DCHECK(MozjsGlobalEnvironment::GetFromContext(context));
- JS::RootedObject global_object(
- context,
- MozjsGlobalEnvironment::GetFromContext(context)->global_object());
- DCHECK(global_object);
-
- InterfaceData* interface_data = GetInterfaceData(context);
- JS::RootedObject prototype(context, GetPrototype(context, global_object));
- DCHECK(prototype);
- JS::RootedObject new_object(context, JS_NewObjectWithGivenProto(
- context, &interface_data->instance_class_definition, prototype, NULL));
- DCHECK(new_object);
- JS::RootedObject proxy(context,
- ProxyHandler::NewProxy(context, new_object, prototype, NULL,
- proxy_handler.Pointer()));
- WrapperPrivate::GetOpaqueRootFunction get_root;
- WrapperPrivate::GetReachableWrappablesFunction get_reachable_wrappables;
- get_root = base::Bind(&GetOpaqueRootFromWrappable);
- get_reachable_wrappables = base::Bind(&GetReachableWrappables);
- WrapperPrivate::AddPrivateData(
- context, proxy, wrappable, get_root, get_reachable_wrappables);
- return proxy;
-}
-
-//static
-const JSClass* MozjsGetOpaqueRootInterface::PrototypeClass(
- JSContext* context) {
- DCHECK(MozjsGlobalEnvironment::GetFromContext(context));
- JS::RootedObject global_object(
- context,
- MozjsGlobalEnvironment::GetFromContext(context)->global_object());
- DCHECK(global_object);
-
- JS::RootedObject prototype(context, GetPrototype(context, global_object));
- JSClass* proto_class = JS_GetClass(*prototype.address());
- return proto_class;
-}
-
-// static
-JSObject* MozjsGetOpaqueRootInterface::GetPrototype(
- JSContext* context, JS::HandleObject global_object) {
- DCHECK(JS_IsGlobalObject(global_object));
-
- InterfaceData* interface_data = GetInterfaceData(context);
- if (!interface_data->prototype) {
- // Create new prototype that has all the props and methods
- InitializePrototypeAndInterfaceObject(
- interface_data, context, global_object);
- }
- DCHECK(interface_data->prototype);
- return interface_data->prototype;
-}
-
-// static
-JSObject* MozjsGetOpaqueRootInterface::GetInterfaceObject(
- JSContext* context, JS::HandleObject global_object) {
- DCHECK(JS_IsGlobalObject(global_object));
-
- InterfaceData* interface_data = GetInterfaceData(context);
- if (!interface_data->interface_object) {
- InitializePrototypeAndInterfaceObject(
- interface_data, context, global_object);
- }
- DCHECK(interface_data->interface_object);
- return interface_data->interface_object;
-}
-
-
-namespace {
-JSBool Constructor(JSContext* context, unsigned int argc, JS::Value* vp) {
- MozjsExceptionState exception_state(context);
- JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
-
- scoped_refptr<GetOpaqueRootInterface> new_object =
- new GetOpaqueRootInterface();
- JS::RootedValue result_value(context);
- ToJSValue(context, new_object, &result_value);
- DCHECK(result_value.isObject());
- JS::RootedObject result_object(context, JSVAL_TO_OBJECT(result_value));
- args.rval().setObject(*result_object);
- return true;
-}
-} // namespace
-
-
-} // namespace testing
-} // namespace bindings
-} // namespace cobalt
diff --git a/src/cobalt/bindings/generated/mozjs/testing/cobalt/bindings/testing/mozjs_get_opaque_root_interface.h b/src/cobalt/bindings/generated/mozjs/testing/cobalt/bindings/testing/mozjs_get_opaque_root_interface.h
deleted file mode 100644
index 7b60f3c..0000000
--- a/src/cobalt/bindings/generated/mozjs/testing/cobalt/bindings/testing/mozjs_get_opaque_root_interface.h
+++ /dev/null
@@ -1,52 +0,0 @@
-// Copyright 2017 Google Inc. All Rights Reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-// clang-format off
-
-// This file has been auto-generated by bindings/code_generator_cobalt.py. DO NOT MODIFY!
-// Auto-generated from template: bindings/mozjs/templates/interface.h.template
-
-#ifndef MozjsGetOpaqueRootInterface_h
-#define MozjsGetOpaqueRootInterface_h
-
-#include "base/hash_tables.h"
-#include "base/lazy_instance.h"
-#include "base/memory/ref_counted.h"
-#include "base/threading/thread_checker.h"
-#include "cobalt/base/polymorphic_downcast.h"
-#include "cobalt/script/wrappable.h"
-#include "cobalt/bindings/testing/get_opaque_root_interface.h"
-
-#include "third_party/mozjs/js/src/jsapi.h"
-
-namespace cobalt {
-namespace bindings {
-namespace testing {
-
-class MozjsGetOpaqueRootInterface {
- public:
- static JSObject* CreateProxy(JSContext* context,
- const scoped_refptr<script::Wrappable>& wrappable);
- static const JSClass* PrototypeClass(JSContext* context);
- static JSObject* GetPrototype(JSContext* context,
- JS::HandleObject global_object);
- static JSObject* GetInterfaceObject(JSContext* context,
- JS::HandleObject global_object);
-};
-
-} // namespace testing
-} // namespace bindings
-} // namespace cobalt
-
-#endif // MozjsGetOpaqueRootInterface_h
diff --git a/src/cobalt/bindings/generated/mozjs/testing/cobalt/bindings/testing/mozjs_window.cc b/src/cobalt/bindings/generated/mozjs/testing/cobalt/bindings/testing/mozjs_window.cc
index 883ae30..bba75f7 100644
--- a/src/cobalt/bindings/generated/mozjs/testing/cobalt/bindings/testing/mozjs_window.cc
+++ b/src/cobalt/bindings/generated/mozjs/testing/cobalt/bindings/testing/mozjs_window.cc
@@ -46,7 +46,6 @@
#include "cobalt/bindings/testing/exceptions_interface.h"
#include "cobalt/bindings/testing/extended_idl_attributes_interface.h"
#include "cobalt/bindings/testing/garbage_collection_test_interface.h"
-#include "cobalt/bindings/testing/get_opaque_root_interface.h"
#include "cobalt/bindings/testing/global_interface_parent.h"
#include "cobalt/bindings/testing/implemented_interface.h"
#include "cobalt/bindings/testing/indexed_getter_interface.h"
@@ -74,7 +73,6 @@
#include "cobalt/bindings/testing/mozjs_exceptions_interface.h"
#include "cobalt/bindings/testing/mozjs_extended_idl_attributes_interface.h"
#include "cobalt/bindings/testing/mozjs_garbage_collection_test_interface.h"
-#include "cobalt/bindings/testing/mozjs_get_opaque_root_interface.h"
#include "cobalt/bindings/testing/mozjs_global_interface_parent.h"
#include "cobalt/bindings/testing/mozjs_implemented_interface.h"
#include "cobalt/bindings/testing/mozjs_indexed_getter_interface.h"
@@ -175,7 +173,6 @@
using cobalt::bindings::testing::ExceptionsInterface;
using cobalt::bindings::testing::ExtendedIDLAttributesInterface;
using cobalt::bindings::testing::GarbageCollectionTestInterface;
-using cobalt::bindings::testing::GetOpaqueRootInterface;
using cobalt::bindings::testing::GlobalInterfaceParent;
using cobalt::bindings::testing::ImplementedInterface;
using cobalt::bindings::testing::IndexedGetterInterface;
@@ -207,7 +204,6 @@
using cobalt::bindings::testing::MozjsExceptionsInterface;
using cobalt::bindings::testing::MozjsExtendedIDLAttributesInterface;
using cobalt::bindings::testing::MozjsGarbageCollectionTestInterface;
-using cobalt::bindings::testing::MozjsGetOpaqueRootInterface;
using cobalt::bindings::testing::MozjsGlobalInterfaceParent;
using cobalt::bindings::testing::MozjsImplementedInterface;
using cobalt::bindings::testing::MozjsIndexedGetterInterface;
@@ -1156,10 +1152,6 @@
base::Bind(MozjsGarbageCollectionTestInterface::CreateProxy),
base::Bind(MozjsGarbageCollectionTestInterface::PrototypeClass));
wrapper_factory->RegisterWrappableType(
- GetOpaqueRootInterface::GetOpaqueRootInterfaceWrappableType(),
- base::Bind(MozjsGetOpaqueRootInterface::CreateProxy),
- base::Bind(MozjsGetOpaqueRootInterface::PrototypeClass));
- wrapper_factory->RegisterWrappableType(
GlobalInterfaceParent::GlobalInterfaceParentWrappableType(),
base::Bind(MozjsGlobalInterfaceParent::CreateProxy),
base::Bind(MozjsGlobalInterfaceParent::PrototypeClass));
diff --git a/src/cobalt/bindings/generated/mozjs45/testing/cobalt/bindings/testing/mozjs_garbage_collection_test_interface.cc b/src/cobalt/bindings/generated/mozjs45/testing/cobalt/bindings/testing/mozjs_garbage_collection_test_interface.cc
index 0c62a2d..e13c005 100644
--- a/src/cobalt/bindings/generated/mozjs45/testing/cobalt/bindings/testing/mozjs_garbage_collection_test_interface.cc
+++ b/src/cobalt/bindings/generated/mozjs45/testing/cobalt/bindings/testing/mozjs_garbage_collection_test_interface.cc
@@ -93,13 +93,6 @@
namespace {
-Wrappable* GetOpaqueRootFromWrappable(
- const scoped_refptr<Wrappable>& wrappable) {
- GarbageCollectionTestInterface* impl =
- base::polymorphic_downcast<GarbageCollectionTestInterface*>(wrappable.get());
- return impl->GetHead();
-}
-
class MozjsGarbageCollectionTestInterfaceHandler : public ProxyHandler {
public:
MozjsGarbageCollectionTestInterfaceHandler()
@@ -515,11 +508,7 @@
JS::RootedObject proxy(context,
ProxyHandler::NewProxy(
context, proxy_handler.Pointer(), new_object, prototype));
- WrapperPrivate::GetOpaqueRootFunction get_root;
- WrapperPrivate::GetReachableWrappablesFunction get_reachable_wrappables;
- get_root = base::Bind(&GetOpaqueRootFromWrappable);
- WrapperPrivate::AddPrivateData(
- context, proxy, wrappable, get_root, get_reachable_wrappables);
+ WrapperPrivate::AddPrivateData(context, proxy, wrappable);
return proxy;
}
diff --git a/src/cobalt/bindings/generated/mozjs45/testing/cobalt/bindings/testing/mozjs_get_opaque_root_interface.cc b/src/cobalt/bindings/generated/mozjs45/testing/cobalt/bindings/testing/mozjs_get_opaque_root_interface.cc
deleted file mode 100644
index f2001fc..0000000
--- a/src/cobalt/bindings/generated/mozjs45/testing/cobalt/bindings/testing/mozjs_get_opaque_root_interface.cc
+++ /dev/null
@@ -1,404 +0,0 @@
-// Copyright 2017 Google Inc. All Rights Reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-// clang-format off
-
-// This file has been auto-generated by bindings/code_generator_cobalt.py. DO NOT MODIFY!
-// Auto-generated from template: bindings/mozjs45/templates/interface.cc.template
-
-#include "cobalt/bindings/testing/mozjs_get_opaque_root_interface.h"
-
-#include "base/debug/trace_event.h"
-#include "cobalt/base/polymorphic_downcast.h"
-#include "cobalt/script/global_environment.h"
-#include "cobalt/script/opaque_handle.h"
-#include "cobalt/script/script_value.h"
-
-#include "mozjs_gen_type_conversion.h"
-
-#include "base/lazy_instance.h"
-#include "cobalt/script/exception_state.h"
-#include "cobalt/script/mozjs-45/callback_function_conversion.h"
-#include "cobalt/script/mozjs-45/conversion_helpers.h"
-#include "cobalt/script/mozjs-45/mozjs_callback_function.h"
-#include "cobalt/script/mozjs-45/mozjs_exception_state.h"
-#include "cobalt/script/mozjs-45/mozjs_global_environment.h"
-#include "cobalt/script/mozjs-45/mozjs_object_handle.h"
-#include "cobalt/script/mozjs-45/mozjs_property_enumerator.h"
-#include "cobalt/script/mozjs-45/mozjs_user_object_holder.h"
-#include "cobalt/script/mozjs-45/mozjs_value_handle.h"
-#include "cobalt/script/mozjs-45/native_promise.h"
-#include "cobalt/script/mozjs-45/proxy_handler.h"
-#include "cobalt/script/mozjs-45/type_traits.h"
-#include "cobalt/script/mozjs-45/wrapper_factory.h"
-#include "cobalt/script/mozjs-45/wrapper_private.h"
-#include "cobalt/script/property_enumerator.h"
-#include "cobalt/script/sequence.h"
-#include "third_party/mozjs-45/js/src/jsapi.h"
-#include "third_party/mozjs-45/js/src/jsfriendapi.h"
-
-namespace {
-using cobalt::bindings::testing::GetOpaqueRootInterface;
-using cobalt::bindings::testing::MozjsGetOpaqueRootInterface;
-using cobalt::script::CallbackInterfaceTraits;
-using cobalt::script::GlobalEnvironment;
-using cobalt::script::OpaqueHandle;
-using cobalt::script::OpaqueHandleHolder;
-using cobalt::script::ScriptValue;
-using cobalt::script::ValueHandle;
-using cobalt::script::Wrappable;
-
-using cobalt::script::CallbackFunction;
-using cobalt::script::CallbackInterfaceTraits;
-using cobalt::script::ExceptionState;
-using cobalt::script::Wrappable;
-using cobalt::script::mozjs::FromJSValue;
-using cobalt::script::mozjs::InterfaceData;
-using cobalt::script::mozjs::MozjsCallbackFunction;
-using cobalt::script::mozjs::MozjsExceptionState;
-using cobalt::script::mozjs::MozjsGlobalEnvironment;
-using cobalt::script::mozjs::MozjsPropertyEnumerator;
-using cobalt::script::mozjs::MozjsUserObjectHolder;
-using cobalt::script::mozjs::ProxyHandler;
-using cobalt::script::mozjs::ToJSValue;
-using cobalt::script::mozjs::TypeTraits;
-using cobalt::script::mozjs::WrapperFactory;
-using cobalt::script::mozjs::WrapperPrivate;
-using cobalt::script::mozjs::kConversionFlagClamped;
-using cobalt::script::mozjs::kConversionFlagNullable;
-using cobalt::script::mozjs::kConversionFlagRestricted;
-using cobalt::script::mozjs::kConversionFlagTreatNullAsEmptyString;
-using cobalt::script::mozjs::kConversionFlagTreatUndefinedAsEmptyString;
-using cobalt::script::mozjs::kNoConversionFlags;
-} // namespace
-
-namespace cobalt {
-namespace bindings {
-namespace testing {
-
-namespace {
-
-Wrappable* GetOpaqueRootFromWrappable(
- const scoped_refptr<Wrappable>& wrappable) {
- GetOpaqueRootInterface* impl =
- base::polymorphic_downcast<GetOpaqueRootInterface*>(wrappable.get());
- return impl->get_opaque_root_function_name();
-}
-
-void GetReachableWrappables(const scoped_refptr<Wrappable>& wrappable,
- WrapperPrivate::WrappableVector* reachable) {
- DCHECK(reachable);
- GetOpaqueRootInterface* impl =
- base::polymorphic_downcast<GetOpaqueRootInterface*>(wrappable.get());
- Wrappable* reachable_0 = impl->add_opaque_root_function_name();
- if (reachable_0) {
- reachable->push_back(reachable_0);
- }
-}
-
-class MozjsGetOpaqueRootInterfaceHandler : public ProxyHandler {
- public:
- MozjsGetOpaqueRootInterfaceHandler()
- : ProxyHandler(indexed_property_hooks, named_property_hooks) {}
-
- private:
- static NamedPropertyHooks named_property_hooks;
- static IndexedPropertyHooks indexed_property_hooks;
-};
-
-ProxyHandler::NamedPropertyHooks
-MozjsGetOpaqueRootInterfaceHandler::named_property_hooks = {
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
-};
-ProxyHandler::IndexedPropertyHooks
-MozjsGetOpaqueRootInterfaceHandler::indexed_property_hooks = {
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
-};
-
-static base::LazyInstance<MozjsGetOpaqueRootInterfaceHandler>
- proxy_handler;
-
-bool Constructor(JSContext* context, unsigned int argc, JS::Value* vp);
-bool HasInstance(JSContext *context, JS::HandleObject type,
- JS::MutableHandleValue vp, bool *success) {
- JS::RootedObject global_object(
- context, JS_GetGlobalForObject(context, type));
- DCHECK(global_object);
-
- JS::RootedObject prototype(
- context, MozjsGetOpaqueRootInterface::GetPrototype(context, global_object));
-
- // |IsDelegate| walks the prototype chain of an object returning true if
- // .prototype is found.
- bool is_delegate;
- if (!IsDelegate(context, prototype, vp, &is_delegate)) {
- *success = false;
- return false;
- }
-
- *success = is_delegate;
- return true;
-}
-
-const JSClass instance_class_definition = {
- "GetOpaqueRootInterface",
- 0 | JSCLASS_HAS_PRIVATE,
- NULL, // addProperty
- NULL, // delProperty
- NULL, // getProperty
- NULL, // setProperty
- NULL, // enumerate
- NULL, // resolve
- NULL, // mayResolve
- &WrapperPrivate::Finalizer, // finalize
- NULL, // call
- NULL, // hasInstance
- NULL, // construct
- &WrapperPrivate::Trace, // trace
-};
-
-const JSClass prototype_class_definition = {
- "GetOpaqueRootInterfacePrototype",
-};
-
-const JSClass interface_object_class_definition = {
- "GetOpaqueRootInterfaceConstructor",
- 0,
- NULL, // addProperty
- NULL, // delProperty
- NULL, // getProperty
- NULL, // setProperty
- NULL, // enumerate
- NULL, // resolve
- NULL, // mayResolve
- NULL, // finalize
- NULL, // call
- &HasInstance,
- Constructor,
-};
-
-
-
-const JSPropertySpec prototype_properties[] = {
- JS_PS_END
-};
-
-const JSFunctionSpec prototype_functions[] = {
- JS_FS_END
-};
-
-const JSPropertySpec interface_object_properties[] = {
- JS_PS_END
-};
-
-const JSFunctionSpec interface_object_functions[] = {
- JS_FS_END
-};
-
-const JSPropertySpec own_properties[] = {
- JS_PS_END
-};
-
-void InitializePrototypeAndInterfaceObject(
- InterfaceData* interface_data, JSContext* context,
- JS::HandleObject global_object) {
- DCHECK(!interface_data->prototype);
- DCHECK(!interface_data->interface_object);
- DCHECK(JS_IsGlobalObject(global_object));
-
- JS::RootedObject parent_prototype(
- context, JS_GetObjectPrototype(context, global_object));
- DCHECK(parent_prototype);
-
- interface_data->prototype = JS_NewObjectWithGivenProto(
- context, &prototype_class_definition, parent_prototype
- );
-
- JS::RootedObject rooted_prototype(context, interface_data->prototype);
- bool success = JS_DefineProperties(
- context,
- rooted_prototype,
- prototype_properties);
-
- DCHECK(success);
- success = JS_DefineFunctions(
- context, rooted_prototype, prototype_functions);
- DCHECK(success);
-
- JS::RootedObject function_prototype(
- context, JS_GetFunctionPrototype(context, global_object));
- DCHECK(function_prototype);
- // Create the Interface object.
- interface_data->interface_object = JS_NewObjectWithGivenProto(
- context, &interface_object_class_definition,
- function_prototype);
-
- // Add the InterfaceObject.name property.
- JS::RootedObject rooted_interface_object(
- context, interface_data->interface_object);
- JS::RootedValue name_value(context);
- const char name[] =
- "GetOpaqueRootInterface";
- name_value.setString(JS_NewStringCopyZ(context, name));
- success = JS_DefineProperty(
- context, rooted_interface_object, "name", name_value, JSPROP_READONLY,
- NULL, NULL);
- DCHECK(success);
-
- // Add the InterfaceObject.length property. It is set to the length of the
- // shortest argument list of all overload constructors.
- JS::RootedValue length_value(context);
- length_value.setInt32(0);
- success = JS_DefineProperty(
- context, rooted_interface_object, "length", length_value,
- JSPROP_READONLY, NULL, NULL);
- DCHECK(success);
-
- // Define interface object properties (including constants).
- success = JS_DefineProperties(context, rooted_interface_object,
- interface_object_properties);
- DCHECK(success);
- // Define interface object functions (static).
- success = JS_DefineFunctions(context, rooted_interface_object,
- interface_object_functions);
- DCHECK(success);
-
- // Set the Prototype.constructor and Constructor.prototype properties.
- DCHECK(interface_data->interface_object);
- DCHECK(interface_data->prototype);
- success = JS_LinkConstructorAndPrototype(
- context,
- rooted_interface_object,
- rooted_prototype);
- DCHECK(success);
-}
-
-InterfaceData* GetInterfaceData(JSContext* context) {
- MozjsGlobalEnvironment* global_environment =
- static_cast<MozjsGlobalEnvironment*>(JS_GetContextPrivate(context));
- // Use the address of the properties definition for this interface as a
- // unique key for looking up the InterfaceData for this interface.
- intptr_t key = reinterpret_cast<intptr_t>(&own_properties);
- InterfaceData* interface_data = global_environment->GetInterfaceData(key);
- if (!interface_data) {
- interface_data = new InterfaceData();
- DCHECK(interface_data);
- global_environment->CacheInterfaceData(key, interface_data);
- DCHECK_EQ(interface_data, global_environment->GetInterfaceData(key));
- }
- return interface_data;
-}
-
-} // namespace
-
-// static
-JSObject* MozjsGetOpaqueRootInterface::CreateProxy(
- JSContext* context, const scoped_refptr<Wrappable>& wrappable) {
- DCHECK(MozjsGlobalEnvironment::GetFromContext(context));
- JS::RootedObject global_object(
- context,
- MozjsGlobalEnvironment::GetFromContext(context)->global_object());
- DCHECK(global_object);
-
- InterfaceData* interface_data = GetInterfaceData(context);
- JS::RootedObject prototype(context, GetPrototype(context, global_object));
- DCHECK(prototype);
- JS::RootedObject new_object(
- context,
- JS_NewObjectWithGivenProto(
- context, &instance_class_definition, prototype));
- DCHECK(new_object);
- JS::RootedObject proxy(context,
- ProxyHandler::NewProxy(
- context, proxy_handler.Pointer(), new_object, prototype));
- WrapperPrivate::GetOpaqueRootFunction get_root;
- WrapperPrivate::GetReachableWrappablesFunction get_reachable_wrappables;
- get_root = base::Bind(&GetOpaqueRootFromWrappable);
- get_reachable_wrappables = base::Bind(&GetReachableWrappables);
- WrapperPrivate::AddPrivateData(
- context, proxy, wrappable, get_root, get_reachable_wrappables);
- return proxy;
-}
-
-// static
-const JSClass* MozjsGetOpaqueRootInterface::PrototypeClass(
- JSContext* context) {
- DCHECK(MozjsGlobalEnvironment::GetFromContext(context));
- JS::RootedObject global_object(
- context,
- MozjsGlobalEnvironment::GetFromContext(context)->global_object());
- DCHECK(global_object);
-
- JS::RootedObject prototype(context, GetPrototype(context, global_object));
- const JSClass* proto_class = JS_GetClass(prototype);
- return proto_class;
-}
-
-// static
-JSObject* MozjsGetOpaqueRootInterface::GetPrototype(
- JSContext* context, JS::HandleObject global_object) {
- DCHECK(JS_IsGlobalObject(global_object));
-
- InterfaceData* interface_data = GetInterfaceData(context);
- if (!interface_data->prototype) {
- // Create new prototype that has all the props and methods
- InitializePrototypeAndInterfaceObject(
- interface_data, context, global_object);
- }
- DCHECK(interface_data->prototype);
- return interface_data->prototype;
-}
-
-// static
-JSObject* MozjsGetOpaqueRootInterface::GetInterfaceObject(
- JSContext* context, JS::HandleObject global_object) {
- DCHECK(JS_IsGlobalObject(global_object));
-
- InterfaceData* interface_data = GetInterfaceData(context);
- if (!interface_data->interface_object) {
- InitializePrototypeAndInterfaceObject(
- interface_data, context, global_object);
- }
- DCHECK(interface_data->interface_object);
- return interface_data->interface_object;
-}
-
-
-namespace {
-bool Constructor(JSContext* context, unsigned int argc, JS::Value* vp) {
- MozjsExceptionState exception_state(context);
- JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
-
- scoped_refptr<GetOpaqueRootInterface> new_object =
- new GetOpaqueRootInterface();
- JS::RootedValue result_value(context);
- ToJSValue(context, new_object, &result_value);
- DCHECK(result_value.isObject());
- args.rval().setObject(result_value.toObject());
- return true;
-}
-} // namespace
-
-
-} // namespace testing
-} // namespace bindings
-} // namespace cobalt
diff --git a/src/cobalt/bindings/generated/mozjs45/testing/cobalt/bindings/testing/mozjs_get_opaque_root_interface.h b/src/cobalt/bindings/generated/mozjs45/testing/cobalt/bindings/testing/mozjs_get_opaque_root_interface.h
deleted file mode 100644
index b5fd99c..0000000
--- a/src/cobalt/bindings/generated/mozjs45/testing/cobalt/bindings/testing/mozjs_get_opaque_root_interface.h
+++ /dev/null
@@ -1,52 +0,0 @@
-// Copyright 2017 Google Inc. All Rights Reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-// clang-format off
-
-// This file has been auto-generated by bindings/code_generator_cobalt.py. DO NOT MODIFY!
-// Auto-generated from template: bindings/mozjs45/templates/interface.h.template
-
-#ifndef MozjsGetOpaqueRootInterface_h
-#define MozjsGetOpaqueRootInterface_h
-
-#include "base/hash_tables.h"
-#include "base/lazy_instance.h"
-#include "base/memory/ref_counted.h"
-#include "base/threading/thread_checker.h"
-#include "cobalt/base/polymorphic_downcast.h"
-#include "cobalt/script/wrappable.h"
-#include "cobalt/bindings/testing/get_opaque_root_interface.h"
-
-#include "third_party/mozjs-45/js/src/jsapi.h"
-
-namespace cobalt {
-namespace bindings {
-namespace testing {
-
-class MozjsGetOpaqueRootInterface {
- public:
- static JSObject* CreateProxy(JSContext* context,
- const scoped_refptr<script::Wrappable>& wrappable);
- static const JSClass* PrototypeClass(JSContext* context);
- static JSObject* GetPrototype(JSContext* context,
- JS::HandleObject global_object);
- static JSObject* GetInterfaceObject(JSContext* context,
- JS::HandleObject global_object);
-};
-
-} // namespace testing
-} // namespace bindings
-} // namespace cobalt
-
-#endif // MozjsGetOpaqueRootInterface_h
diff --git a/src/cobalt/bindings/generated/mozjs45/testing/cobalt/bindings/testing/mozjs_window.cc b/src/cobalt/bindings/generated/mozjs45/testing/cobalt/bindings/testing/mozjs_window.cc
index c26f450..1414c2c 100644
--- a/src/cobalt/bindings/generated/mozjs45/testing/cobalt/bindings/testing/mozjs_window.cc
+++ b/src/cobalt/bindings/generated/mozjs45/testing/cobalt/bindings/testing/mozjs_window.cc
@@ -46,7 +46,6 @@
#include "cobalt/bindings/testing/exceptions_interface.h"
#include "cobalt/bindings/testing/extended_idl_attributes_interface.h"
#include "cobalt/bindings/testing/garbage_collection_test_interface.h"
-#include "cobalt/bindings/testing/get_opaque_root_interface.h"
#include "cobalt/bindings/testing/global_interface_parent.h"
#include "cobalt/bindings/testing/implemented_interface.h"
#include "cobalt/bindings/testing/indexed_getter_interface.h"
@@ -74,7 +73,6 @@
#include "cobalt/bindings/testing/mozjs_exceptions_interface.h"
#include "cobalt/bindings/testing/mozjs_extended_idl_attributes_interface.h"
#include "cobalt/bindings/testing/mozjs_garbage_collection_test_interface.h"
-#include "cobalt/bindings/testing/mozjs_get_opaque_root_interface.h"
#include "cobalt/bindings/testing/mozjs_global_interface_parent.h"
#include "cobalt/bindings/testing/mozjs_implemented_interface.h"
#include "cobalt/bindings/testing/mozjs_indexed_getter_interface.h"
@@ -175,7 +173,6 @@
using cobalt::bindings::testing::ExceptionsInterface;
using cobalt::bindings::testing::ExtendedIDLAttributesInterface;
using cobalt::bindings::testing::GarbageCollectionTestInterface;
-using cobalt::bindings::testing::GetOpaqueRootInterface;
using cobalt::bindings::testing::GlobalInterfaceParent;
using cobalt::bindings::testing::ImplementedInterface;
using cobalt::bindings::testing::IndexedGetterInterface;
@@ -207,7 +204,6 @@
using cobalt::bindings::testing::MozjsExceptionsInterface;
using cobalt::bindings::testing::MozjsExtendedIDLAttributesInterface;
using cobalt::bindings::testing::MozjsGarbageCollectionTestInterface;
-using cobalt::bindings::testing::MozjsGetOpaqueRootInterface;
using cobalt::bindings::testing::MozjsGlobalInterfaceParent;
using cobalt::bindings::testing::MozjsImplementedInterface;
using cobalt::bindings::testing::MozjsIndexedGetterInterface;
@@ -1157,10 +1153,6 @@
base::Bind(MozjsGarbageCollectionTestInterface::CreateProxy),
base::Bind(MozjsGarbageCollectionTestInterface::PrototypeClass));
wrapper_factory->RegisterWrappableType(
- GetOpaqueRootInterface::GetOpaqueRootInterfaceWrappableType(),
- base::Bind(MozjsGetOpaqueRootInterface::CreateProxy),
- base::Bind(MozjsGetOpaqueRootInterface::PrototypeClass));
- wrapper_factory->RegisterWrappableType(
GlobalInterfaceParent::GlobalInterfaceParentWrappableType(),
base::Bind(MozjsGlobalInterfaceParent::CreateProxy),
base::Bind(MozjsGlobalInterfaceParent::PrototypeClass));
diff --git a/src/cobalt/bindings/mozjs/templates/interface.cc.template b/src/cobalt/bindings/mozjs/templates/interface.cc.template
index 12ad4c0..99ca683 100644
--- a/src/cobalt/bindings/mozjs/templates/interface.cc.template
+++ b/src/cobalt/bindings/mozjs/templates/interface.cc.template
@@ -90,30 +90,6 @@
{% block implementation %}
namespace {
-{% if get_opaque_root %}
-Wrappable* GetOpaqueRootFromWrappable(
- const scoped_refptr<Wrappable>& wrappable) {
- {{impl_class}}* impl =
- base::polymorphic_downcast<{{impl_class}}*>(wrappable.get());
- return impl->{{get_opaque_root}}();
-}
-
-{% endif %}
-{% if add_opaque_roots %}
-void GetReachableWrappables(const scoped_refptr<Wrappable>& wrappable,
- WrapperPrivate::WrappableVector* reachable) {
- DCHECK(reachable);
- {{impl_class}}* impl =
- base::polymorphic_downcast<{{impl_class}}*>(wrappable.get());
-{% for reachable_object in add_opaque_roots %}
- Wrappable* reachable_{{loop.index0}} = impl->{{reachable_object}}();
- if (reachable_{{loop.index0}}) {
- reachable->push_back(reachable_{{loop.index0}});
- }
-{% endfor %}
-}
-
-{% endif %}
{% if named_property_getter %}
bool IsSupportedNamedProperty(JSContext* context, JS::HandleObject object,
const std::string& property_name) {
@@ -843,20 +819,7 @@
JS::RootedObject proxy(context,
ProxyHandler::NewProxy(context, new_object, prototype, NULL,
proxy_handler.Pointer()));
-{% if add_opaque_roots or get_opaque_root %}
- WrapperPrivate::GetOpaqueRootFunction get_root;
- WrapperPrivate::GetReachableWrappablesFunction get_reachable_wrappables;
-{% if get_opaque_root %}
- get_root = base::Bind(&GetOpaqueRootFromWrappable);
-{% endif %}
-{% if add_opaque_roots %}
- get_reachable_wrappables = base::Bind(&GetReachableWrappables);
-{% endif %}
- WrapperPrivate::AddPrivateData(
- context, proxy, wrappable, get_root, get_reachable_wrappables);
-{% else %}
WrapperPrivate::AddPrivateData(context, proxy, wrappable);
-{% endif %}
return proxy;
}
diff --git a/src/cobalt/bindings/mozjs45/templates/interface.cc.template b/src/cobalt/bindings/mozjs45/templates/interface.cc.template
index 6296ec9..abe82f9 100644
--- a/src/cobalt/bindings/mozjs45/templates/interface.cc.template
+++ b/src/cobalt/bindings/mozjs45/templates/interface.cc.template
@@ -105,30 +105,6 @@
{% block implementation %}
namespace {
-{% if get_opaque_root %}
-Wrappable* GetOpaqueRootFromWrappable(
- const scoped_refptr<Wrappable>& wrappable) {
- {{impl_class}}* impl =
- base::polymorphic_downcast<{{impl_class}}*>(wrappable.get());
- return impl->{{get_opaque_root}}();
-}
-
-{% endif %}
-{% if add_opaque_roots %}
-void GetReachableWrappables(const scoped_refptr<Wrappable>& wrappable,
- WrapperPrivate::WrappableVector* reachable) {
- DCHECK(reachable);
- {{impl_class}}* impl =
- base::polymorphic_downcast<{{impl_class}}*>(wrappable.get());
-{% for reachable_object in add_opaque_roots %}
- Wrappable* reachable_{{loop.index0}} = impl->{{reachable_object}}();
- if (reachable_{{loop.index0}}) {
- reachable->push_back(reachable_{{loop.index0}});
- }
-{% endfor %}
-}
-
-{% endif %}
{% if named_property_getter %}
bool IsSupportedNamedProperty(JSContext* context, JS::HandleObject object,
const std::string& property_name) {
@@ -861,20 +837,7 @@
JS::RootedObject proxy(context,
ProxyHandler::NewProxy(
context, proxy_handler.Pointer(), new_object, prototype));
-{% if add_opaque_roots or get_opaque_root %}
- WrapperPrivate::GetOpaqueRootFunction get_root;
- WrapperPrivate::GetReachableWrappablesFunction get_reachable_wrappables;
-{% if get_opaque_root %}
- get_root = base::Bind(&GetOpaqueRootFromWrappable);
-{% endif %}
-{% if add_opaque_roots %}
- get_reachable_wrappables = base::Bind(&GetReachableWrappables);
-{% endif %}
- WrapperPrivate::AddPrivateData(
- context, proxy, wrappable, get_root, get_reachable_wrappables);
-{% else %}
WrapperPrivate::AddPrivateData(context, proxy, wrappable);
-{% endif %}
return proxy;
}
diff --git a/src/cobalt/bindings/templates/dictionary.h.template b/src/cobalt/bindings/templates/dictionary.h.template
index 2999e8b..686ed73 100644
--- a/src/cobalt/bindings/templates/dictionary.h.template
+++ b/src/cobalt/bindings/templates/dictionary.h.template
@@ -62,7 +62,11 @@
namespace {{component}} {
{% endfor %}
+{% if parent %}
+class {{class_name}} : public {{parent}} {
+{% else %}
class {{class_name}} {
+{% endif %}
public:
{{class_name}}() {
{% for member in members %}
diff --git a/src/cobalt/bindings/testing/garbage_collection_test_interface.cc b/src/cobalt/bindings/testing/garbage_collection_test_interface.cc
index 2bc0177..75b7da9 100644
--- a/src/cobalt/bindings/testing/garbage_collection_test_interface.cc
+++ b/src/cobalt/bindings/testing/garbage_collection_test_interface.cc
@@ -58,15 +58,6 @@
Join(this, next.get());
}
-// The value of |GetOpaqueRoot| in the .idl. This ensures that nodes in the
-// same list have the same "root".
-script::Wrappable* GarbageCollectionTestInterface::GetHead() {
- if (previous_) {
- return previous_->GetHead();
- }
- return this;
-}
-
void GarbageCollectionTestInterface::MakeHead() {
if (previous_) {
DCHECK(previous_->next_ == this);
@@ -99,6 +90,11 @@
return ::cobalt::bindings::testing::instances.Get();
}
+void GarbageCollectionTestInterface::TraceMembers(script::Tracer* tracer) {
+ tracer->Trace(previous_);
+ tracer->Trace(next_);
+}
+
} // namespace testing
} // namespace bindings
} // namespace cobalt
diff --git a/src/cobalt/bindings/testing/garbage_collection_test_interface.h b/src/cobalt/bindings/testing/garbage_collection_test_interface.h
index b976041..337d290 100644
--- a/src/cobalt/bindings/testing/garbage_collection_test_interface.h
+++ b/src/cobalt/bindings/testing/garbage_collection_test_interface.h
@@ -45,12 +45,10 @@
void set_next(const scoped_refptr<GarbageCollectionTestInterface>& next);
scoped_refptr<GarbageCollectionTestInterface> next() { return next_; }
- // The value of |GetOpaqueRoot| in the .idl. This ensures that nodes in the
- // same list have the same "root".
- script::Wrappable* GetHead();
-
static GarbageCollectionTestInterfaceVector& instances();
+ void TraceMembers(script::Tracer* tracer) OVERRIDE;
+
DEFINE_WRAPPABLE_TYPE(GarbageCollectionTestInterface);
private:
diff --git a/src/cobalt/bindings/testing/garbage_collection_test_interface.idl b/src/cobalt/bindings/testing/garbage_collection_test_interface.idl
index 3806100..bace8ed 100644
--- a/src/cobalt/bindings/testing/garbage_collection_test_interface.idl
+++ b/src/cobalt/bindings/testing/garbage_collection_test_interface.idl
@@ -13,12 +13,10 @@
// limitations under the License.
[
Constructor,
- // The head of the list is the "opaque root" of all nodes in the list.
- GetOpaqueRoot=GetHead,
]
interface GarbageCollectionTestInterface {
// This interface represents a simple linked-list implementation used for
- // tests around reachability of objects from opaque roots.
+ // tests around reachability of objects via |TraceMembers|.
attribute GarbageCollectionTestInterface? previous;
attribute GarbageCollectionTestInterface? next;
};
diff --git a/src/cobalt/bindings/testing/get_opaque_root_interface.h b/src/cobalt/bindings/testing/get_opaque_root_interface.h
deleted file mode 100644
index 4c74c3d..0000000
--- a/src/cobalt/bindings/testing/get_opaque_root_interface.h
+++ /dev/null
@@ -1,37 +0,0 @@
-// 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_BINDINGS_TESTING_GET_OPAQUE_ROOT_INTERFACE_H_
-#define COBALT_BINDINGS_TESTING_GET_OPAQUE_ROOT_INTERFACE_H_
-
-#include "cobalt/script/wrappable.h"
-#include "testing/gmock/include/gmock/gmock.h"
-
-namespace cobalt {
-namespace bindings {
-namespace testing {
-
-class GetOpaqueRootInterface : public script::Wrappable {
- public:
- MOCK_METHOD0(get_opaque_root_function_name, script::Wrappable*());
- MOCK_METHOD0(add_opaque_root_function_name, script::Wrappable*());
-
- DEFINE_WRAPPABLE_TYPE(GetOpaqueRootInterface);
-};
-
-} // namespace testing
-} // namespace bindings
-} // namespace cobalt
-
-#endif // COBALT_BINDINGS_TESTING_GET_OPAQUE_ROOT_INTERFACE_H_
diff --git a/src/cobalt/bindings/testing/get_opaque_root_interface.idl b/src/cobalt/bindings/testing/get_opaque_root_interface.idl
deleted file mode 100644
index 2dca51b..0000000
--- a/src/cobalt/bindings/testing/get_opaque_root_interface.idl
+++ /dev/null
@@ -1,21 +0,0 @@
-// 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.
-
-// Constructor attribute is added for test purposes.
-[
- Constructor,
- AddOpaqueRoots=(add_opaque_root_function_name),
- GetOpaqueRoot=get_opaque_root_function_name
-]
-interface GetOpaqueRootInterface {};
diff --git a/src/cobalt/bindings/testing/get_opaque_root_test.cc b/src/cobalt/bindings/testing/get_opaque_root_test.cc
deleted file mode 100644
index e46a11e..0000000
--- a/src/cobalt/bindings/testing/get_opaque_root_test.cc
+++ /dev/null
@@ -1,48 +0,0 @@
-// 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/bindings/testing/bindings_test_base.h"
-#include "cobalt/bindings/testing/get_opaque_root_interface.h"
-
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace cobalt {
-namespace bindings {
-namespace testing {
-
-namespace {
-class GetOpaqueRootInterfaceTest : public BindingsTestBase {
- public:
- GetOpaqueRootInterfaceTest()
- : test_mock_(new ::testing::NiceMock<GetOpaqueRootInterface>()) {
- global_environment_->Bind(
- "test", make_scoped_refptr<GetOpaqueRootInterface>((test_mock_)));
- }
-
- GetOpaqueRootInterface& test_mock() { return *test_mock_.get(); }
-
- private:
- const scoped_refptr<GetOpaqueRootInterface> test_mock_;
-};
-} // namespace
-
-TEST_F(GetOpaqueRootInterfaceTest, CallsFunction) {
- EXPECT_CALL(test_mock(), add_opaque_root_function_name())
- .Times(::testing::AtLeast(1));
- CollectGarbage();
-}
-
-} // namespace testing
-} // namespace bindings
-} // namespace cobalt
diff --git a/src/cobalt/bindings/testing/testing.gyp b/src/cobalt/bindings/testing/testing.gyp
index c32311a..bc92e7c 100644
--- a/src/cobalt/bindings/testing/testing.gyp
+++ b/src/cobalt/bindings/testing/testing.gyp
@@ -47,7 +47,6 @@
'exceptions_interface.idl',
'extended_idl_attributes_interface.idl',
'garbage_collection_test_interface.idl',
- 'get_opaque_root_interface.idl',
'global_interface_parent.idl',
'indexed_getter_interface.idl',
'interface_with_any.idl',
@@ -157,7 +156,6 @@
'exceptions_bindings_test.cc',
'extended_attributes_test.cc',
'garbage_collection_test.cc',
- 'get_opaque_root_test.cc',
'get_own_property_descriptor.cc',
'getter_setter_test.cc',
'global_interface_bindings_test.cc',
diff --git a/src/cobalt/browser/browser.gyp b/src/cobalt/browser/browser.gyp
index 3e5aad6..61b714e 100644
--- a/src/cobalt/browser/browser.gyp
+++ b/src/cobalt/browser/browser.gyp
@@ -49,10 +49,13 @@
'memory_tracker/tool/buffered_file_writer.h',
'memory_tracker/tool/compressed_time_series_tool.cc',
'memory_tracker/tool/compressed_time_series_tool.h',
+ 'memory_tracker/tool/histogram_table_csv_base.h',
'memory_tracker/tool/leak_finder_tool.cc',
'memory_tracker/tool/leak_finder_tool.h',
'memory_tracker/tool/log_writer_tool.cc',
'memory_tracker/tool/log_writer_tool.h',
+ 'memory_tracker/tool/malloc_stats_tool.cc',
+ 'memory_tracker/tool/malloc_stats_tool.h',
'memory_tracker/tool/memory_size_binner_tool.cc',
'memory_tracker/tool/memory_size_binner_tool.h',
'memory_tracker/tool/params.cc',
diff --git a/src/cobalt/browser/browser_bindings_gen.gyp b/src/cobalt/browser/browser_bindings_gen.gyp
index 685296f..294a22c 100644
--- a/src/cobalt/browser/browser_bindings_gen.gyp
+++ b/src/cobalt/browser/browser_bindings_gen.gyp
@@ -211,6 +211,7 @@
'../audio/audio_node_channel_interpretation.idl',
'../dom/blob_property_bag.idl',
'../dom/dom_parser_supported_type.idl',
+ '../dom/event_init.idl',
'../dom/media_source_end_of_stream_error.idl',
'../dom/media_source_ready_state.idl',
'../dom/mutation_observer_init.idl',
diff --git a/src/cobalt/browser/memory_settings/auto_mem.cc b/src/cobalt/browser/memory_settings/auto_mem.cc
index 71a4570..5743645 100644
--- a/src/cobalt/browser/memory_settings/auto_mem.cc
+++ b/src/cobalt/browser/memory_settings/auto_mem.cc
@@ -114,12 +114,18 @@
}
void EnsureValuePositive(IntSetting* setting) {
+ if (!setting->valid()) {
+ return;
+ }
if (setting->value() < 0) {
setting->set_value(setting->source_type(), 0);
}
}
void EnsureValuePositive(DimensionSetting* setting) {
+ if (!setting->valid()) {
+ return;
+ }
const TextureDimensions value = setting->value();
if (value.width() < 0 || value.height() < 0 || value.bytes_per_pixel() < 0) {
setting->set_value(setting->source_type(), TextureDimensions());
@@ -127,6 +133,9 @@
}
void EnsureTwoBytesPerPixel(DimensionSetting* setting) {
+ if (!setting->valid()) {
+ return;
+ }
TextureDimensions value = setting->value();
if (value.bytes_per_pixel() != 2) {
LOG(ERROR) << "Only two bytes per pixel are allowed for setting: "
@@ -151,7 +160,6 @@
return sum;
}
-
// Creates the GPU setting.
// This setting is unique because it may not be defined by command line, or
// build. In this was, it can be unset.
diff --git a/src/cobalt/browser/memory_tracker/tool.cc b/src/cobalt/browser/memory_tracker/tool.cc
index e37356a..5083f99 100644
--- a/src/cobalt/browser/memory_tracker/tool.cc
+++ b/src/cobalt/browser/memory_tracker/tool.cc
@@ -23,11 +23,13 @@
#include "cobalt/browser/memory_tracker/tool/compressed_time_series_tool.h"
#include "cobalt/browser/memory_tracker/tool/leak_finder_tool.h"
#include "cobalt/browser/memory_tracker/tool/log_writer_tool.h"
+#include "cobalt/browser/memory_tracker/tool/malloc_stats_tool.h"
#include "cobalt/browser/memory_tracker/tool/memory_size_binner_tool.h"
#include "cobalt/browser/memory_tracker/tool/print_csv_tool.h"
#include "cobalt/browser/memory_tracker/tool/print_tool.h"
#include "cobalt/browser/memory_tracker/tool/tool_impl.h"
#include "cobalt/browser/memory_tracker/tool/tool_thread.h"
+
#include "nb/analytics/memory_tracker_helpers.h"
#include "nb/lexical_cast.h"
#include "starboard/log.h"
@@ -62,6 +64,7 @@
kAllocationLogger,
kLeakTracer,
kJavascriptLeakTracer,
+ kMallocStats,
};
struct SwitchVal {
@@ -185,6 +188,12 @@
"Automatically detects Javascript leaks and reports them in CSV format.",
kJavascriptLeakTracer);
+ SwitchVal malloc_stats_tool(
+ "malloc_stats",
+ "Queries the allocation system for memory usage. This is the most "
+ "lightweight tool. Output is CSV format.",
+ kMallocStats);
+
SwitchMap switch_map;
switch_map[ParseToolName(startup_tool.tool_name)] = startup_tool;
switch_map[ParseToolName(continuous_printer_tool.tool_name)] =
@@ -198,6 +207,8 @@
switch_map[ParseToolName(js_leak_tracing_tool.tool_name)] =
js_leak_tracing_tool;
+ switch_map[ParseToolName(malloc_stats_tool.tool_name)] = malloc_stats_tool;
+
std::string tool_name = ParseToolName(command_arg);
std::string tool_arg = ParseToolArg(command_arg);
@@ -346,6 +357,10 @@
tool_ptr.reset(leak_finder.release());
break;
}
+ case kMallocStats: {
+ tool_ptr.reset(new MallocStatsTool);
+ break;
+ }
default: {
SB_NOTREACHED() << "Unhandled case.";
break;
diff --git a/src/cobalt/browser/memory_tracker/tool/histogram_table_csv_base.h b/src/cobalt/browser/memory_tracker/tool/histogram_table_csv_base.h
new file mode 100644
index 0000000..0c8ef3e
--- /dev/null
+++ b/src/cobalt/browser/memory_tracker/tool/histogram_table_csv_base.h
@@ -0,0 +1,178 @@
+// Copyright 2017 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef COBALT_BROWSER_MEMORY_TRACKER_TOOL_HISTOGRAM_TABLE_CSV_BASE_H_
+#define COBALT_BROWSER_MEMORY_TRACKER_TOOL_HISTOGRAM_TABLE_CSV_BASE_H_
+
+#include <map>
+#include <sstream>
+#include <string>
+#include <vector>
+
+#include "base/logging.h"
+#include "cobalt/browser/memory_tracker/tool/util.h"
+#include "starboard/types.h"
+
+namespace cobalt {
+namespace browser {
+namespace memory_tracker {
+
+// This HistogramTableCSV provides most of the functionality for generating a
+// csv table from a histogram of data.
+//
+// Subclasses need to override ValueToString(...) so that the
+// data-type can be stringified during the call to ToString().
+//
+// Example:
+// class MyHistogram : public HistogramTableCSV<int64_t>() {...}
+// MyHistogram my_histogram;
+// my_histogram.set_title("Memory Values");
+//
+// // Add first row.
+// my_histogram.BeginRow(time_delta);
+// my_histogram.AddRowValue("ColumnA", 0);
+// my_histogram.AddRowValue("ColumnB", 0);
+// my_histogram.FinilizeRow();
+//
+// // Add second row.
+// my_histogram.BeginRow(time_delta);
+// my_histogram.AddRowValue("ColumnA", 1);
+// my_histogram.AddRowValue("ColumnB", 2);
+// my_histogram.AddRowValue("ColumnC", 1); // Ok, ColumnC will be autofilled.
+// my_histogram.FinilizeRow();
+//
+// Print(my_histogram.ToString());
+template <typename ValueType>
+class HistogramTableCSVBase {
+ public:
+ typedef std::map<std::string, std::vector<ValueType> > TableData;
+
+ // default_value is used to auto-fill values, such as when a new column
+ // is introduced.
+ explicit HistogramTableCSVBase(const ValueType& default_value)
+ : default_value_(default_value) {}
+
+ virtual std::string ValueToString(const ValueType& value) const = 0;
+
+ void set_title(const std::string& title) {
+ title_ = title;
+ }
+
+ void BeginRow(const base::TimeDelta time_value) {
+ time_values_.push_back(time_value);
+ }
+
+ void AddRowValue(const std::string& column_key, const ValueType& value) {
+ if (time_values_.empty()) {
+ NOTREACHED() << "table_data_ was empty.";
+ time_values_.push_back(base::TimeDelta());
+ }
+ const size_t n = time_values_.size();
+ std::vector<ValueType>& column = table_data_[column_key];
+ while (column.size() < n-1) {
+ column.push_back(default_value_);
+ }
+ column.push_back(value);
+ }
+
+ void FinalizeRow() {
+ const size_t n = time_values_.size();
+ for (typename TableData::iterator it = table_data_.begin();
+ it != table_data_.end(); ++it) {
+ std::vector<ValueType>& column = it->second;
+ while (column.size() < n) {
+ column.push_back(default_value_);
+ }
+ }
+ }
+
+ std::string ToString() const {
+ const char kSeperator[] = "//////////////////////////////////////////////";
+ std::stringstream ss;
+ ss << kSeperator << kNewLine;
+ if (title_.size()) {
+ ss << "// CSV of " << title_ << kNewLine;
+ }
+ for (size_t i = 0; i < NumberOfRows(); ++i) {
+ ss << StringifyRow(i);
+ }
+ ss << kSeperator;
+ return ss.str();
+ }
+
+ // All odd elements are removed. Effectively compressing the table in half.
+ void RemoveOddElements() {
+ memory_tracker::RemoveOddElements(&time_values_);
+ for (typename TableData::iterator it = table_data_.begin();
+ it != table_data_.end(); ++it) {
+ memory_tracker::RemoveOddElements(&it->second);
+ }
+ }
+
+ size_t NumberOfRows() const {
+ return time_values_.size();
+ }
+
+ protected:
+ static std::string JoinValues(const std::vector<std::string>& row_values) {
+ std::stringstream ss;
+ for (size_t i = 0; i < row_values.size(); ++i) {
+ ss << kQuote << row_values[i] << kQuote << kDelimiter;
+ }
+ ss << kNewLine;
+ return ss.str();
+ }
+
+ static std::string TimeToMinutesString(base::TimeDelta dt) {
+ double value_minutes = dt.InSecondsF() / 60.;
+ char buff[128];
+ SbStringFormatF(buff, sizeof(buff), "%.2f", value_minutes);
+ return std::string(buff);
+ }
+
+ std::string StringifyRow(size_t index) const {
+ if (index == 0) {
+ // Create header row.
+ std::vector<std::string> column_keys;
+ column_keys.push_back("Time(min)");
+ for (typename TableData::const_iterator it = table_data_.begin();
+ it != table_data_.end(); ++it) {
+ column_keys.push_back(SanitizeCSVKey(it->first));
+ }
+ return JoinValues(column_keys);
+ } else {
+ // Create data row.
+ std::vector<std::string> row_values;
+ row_values.push_back(TimeToMinutesString(time_values_[index]));
+ for (typename TableData::const_iterator it = table_data_.begin();
+ it != table_data_.end(); ++it) {
+ const std::vector<ValueType>& column = it->second;
+ const std::string value_str = ValueToString(column[index]);
+ row_values.push_back(value_str);
+ }
+ return JoinValues(row_values);
+ }
+ }
+
+ std::string title_;
+ ValueType default_value_;
+ std::vector<base::TimeDelta> time_values_;
+ TableData table_data_;
+};
+
+} // namespace memory_tracker
+} // namespace browser
+} // namespace cobalt
+
+#endif // COBALT_BROWSER_MEMORY_TRACKER_TOOL_HISTOGRAM_TABLE_CSV_BASE_H_
diff --git a/src/cobalt/browser/memory_tracker/tool/malloc_stats_tool.cc b/src/cobalt/browser/memory_tracker/tool/malloc_stats_tool.cc
new file mode 100644
index 0000000..5c77791
--- /dev/null
+++ b/src/cobalt/browser/memory_tracker/tool/malloc_stats_tool.cc
@@ -0,0 +1,112 @@
+// Copyright 2017 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "cobalt/browser/memory_tracker/tool/malloc_stats_tool.h"
+
+#include <string>
+#include <vector>
+
+#include "cobalt/browser/memory_tracker/tool/histogram_table_csv_base.h"
+#include "cobalt/browser/memory_tracker/tool/params.h"
+#include "cobalt/browser/memory_tracker/tool/tool_impl.h"
+#include "nb/analytics/memory_tracker.h"
+#include "starboard/string.h"
+#include "starboard/types.h"
+
+namespace cobalt {
+namespace browser {
+namespace memory_tracker {
+namespace {
+
+// Takes in bytes -> outputs as megabytes.
+class MemoryBytesHistogramCSV : public HistogramTableCSVBase<int64_t> {
+ public:
+ MemoryBytesHistogramCSV() : HistogramTableCSVBase<int64_t>(0) {}
+ std::string ValueToString(const int64_t& bytes) const OVERRIDE {
+ return ToMegabyteString(bytes);
+ }
+
+ static std::string ToMegabyteString(int64_t bytes) {
+ double mega_bytes = static_cast<double>(bytes) / (1024.0 * 1024.0);
+ char buff[128];
+ SbStringFormatF(buff, sizeof(buff), "%.1f", mega_bytes);
+ return std::string(buff);
+ }
+};
+
+} // namespace.
+
+MallocStatsTool::MallocStatsTool() {
+}
+
+std::string MallocStatsTool::tool_name() const {
+ return "MallocStatsTool";
+}
+
+void MallocStatsTool::Run(Params* params) {
+ // Run function does almost nothing.
+ params->logger()->Output("MallocStatsTool running...");
+
+ Timer output_timer(base::TimeDelta::FromSeconds(30));
+ Timer sample_timer(base::TimeDelta::FromMilliseconds(50));
+
+ MemoryBytesHistogramCSV histogram_table;
+ histogram_table.set_title("Malloc Stats");
+
+ // If we get a finish signal then this will break out of the loop.
+ while (!params->wait_for_finish_signal(250 * kSbTimeMillisecond)) {
+ // LOG CSV.
+ if (output_timer.UpdateAndIsExpired()) {
+ std::stringstream ss;
+ ss << kNewLine << histogram_table.ToString() << kNewLine << kNewLine;
+ params->logger()->Output(ss.str());
+ }
+
+ // ADD A HISTOGRAM SAMPLE.
+ if (sample_timer.UpdateAndIsExpired()) {
+ // Take a sample.
+ nb::analytics::MemoryStats memory_stats =
+ nb::analytics::GetProcessMemoryStats();
+
+ histogram_table.BeginRow(params->time_since_start());
+ histogram_table.AddRowValue(
+ "TotalCpuMemory(MB)", memory_stats.total_cpu_memory);
+ histogram_table.AddRowValue(
+ "UsedCpuMemory(MB)", memory_stats.used_cpu_memory);
+ histogram_table.AddRowValue(
+ "TotalGpuMemory(MB)", memory_stats.total_gpu_memory);
+ histogram_table.AddRowValue(
+ "UsedGpuMemory(MB)", memory_stats.used_gpu_memory);
+ histogram_table.FinalizeRow();
+ }
+
+ // COMPRESS TABLE WHEN FULL.
+ //
+ // Table is full, therefore eliminate half of the elements.
+ // Reduce sample frequency to match.
+ if (histogram_table.NumberOfRows() >= 100) {
+ // Compression step.
+ histogram_table.RemoveOddElements();
+
+ // By double the sampling time this keeps the table linear with
+ // respect to time. If sampling time was not doubled then there
+ // would be time distortion in the graph.
+ sample_timer.ScaleTimerAndReset(2.0);
+ }
+ }
+}
+
+} // namespace memory_tracker
+} // namespace browser
+} // namespace cobalt
diff --git a/src/cobalt/browser/memory_tracker/tool/malloc_stats_tool.h b/src/cobalt/browser/memory_tracker/tool/malloc_stats_tool.h
new file mode 100644
index 0000000..85381f9
--- /dev/null
+++ b/src/cobalt/browser/memory_tracker/tool/malloc_stats_tool.h
@@ -0,0 +1,41 @@
+// Copyright 2017 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef COBALT_BROWSER_MEMORY_TRACKER_TOOL_MALLOC_STATS_TOOL_H_
+#define COBALT_BROWSER_MEMORY_TRACKER_TOOL_MALLOC_STATS_TOOL_H_
+
+#include <string>
+
+#include "cobalt/browser/memory_tracker/tool/params.h"
+#include "cobalt/browser/memory_tracker/tool/tool_impl.h"
+
+namespace cobalt {
+namespace browser {
+namespace memory_tracker {
+
+// Generates a CSV table of the memory stats. This tool does not use
+// per-allocation tracking and therefore has a lower memory footprint than
+// most other tools.
+class MallocStatsTool : public AbstractTool {
+ public:
+ MallocStatsTool();
+ std::string tool_name() const OVERRIDE;
+ void Run(Params* params) OVERRIDE;
+};
+
+} // namespace memory_tracker
+} // namespace browser
+} // namespace cobalt
+
+#endif // COBALT_BROWSER_MEMORY_TRACKER_TOOL_MALLOC_STATS_TOOL_H_
diff --git a/src/cobalt/browser/memory_tracker/tool/tool_impl.h b/src/cobalt/browser/memory_tracker/tool/tool_impl.h
index 9edef18..b8d4ad3 100644
--- a/src/cobalt/browser/memory_tracker/tool/tool_impl.h
+++ b/src/cobalt/browser/memory_tracker/tool/tool_impl.h
@@ -58,6 +58,7 @@
public:
virtual ~AbstractLogger() {}
virtual void Output(const char* str) = 0;
+ void Output(const std::string& str) { Output(str.c_str()); }
virtual void Flush() = 0;
};
diff --git a/src/cobalt/browser/memory_tracker/tool/util.cc b/src/cobalt/browser/memory_tracker/tool/util.cc
index 09068cb..b25c481 100644
--- a/src/cobalt/browser/memory_tracker/tool/util.cc
+++ b/src/cobalt/browser/memory_tracker/tool/util.cc
@@ -93,15 +93,23 @@
return ss.str();
}
-Timer::Timer(base::TimeDelta dt)
- : start_time_(base::TimeTicks::Now()), time_before_expiration_(dt) {}
+Timer::Timer(base::TimeDelta delta_time) {
+ start_time_ = Now();
+ time_before_expiration_ = delta_time;
+}
-void Timer::Restart() { start_time_ = base::TimeTicks::Now(); }
+Timer::Timer(base::TimeDelta delta_time, Timer::TimeFunctor time_functor) {
+ time_function_override_ = time_functor;
+ start_time_ = Now();
+ time_before_expiration_ = delta_time;
+}
+
+void Timer::Restart() { start_time_ = Now(); }
bool Timer::UpdateAndIsExpired() {
- base::TimeTicks now_time = base::TimeTicks::Now();
- base::TimeDelta dt = now_time - start_time_;
- if (dt > time_before_expiration_) {
+ base::TimeTicks now_time = Now();
+ base::TimeDelta delta_time = now_time - start_time_;
+ if (delta_time >= time_before_expiration_) {
start_time_ = now_time;
return true;
} else {
@@ -109,6 +117,22 @@
}
}
+base::TimeTicks Timer::Now() {
+ if (time_function_override_.is_null()) {
+ return base::TimeTicks::HighResNow();
+ } else {
+ return time_function_override_.Run();
+ }
+}
+
+void Timer::ScaleTimerAndReset(double scale) {
+ int64_t old_dt = time_before_expiration_.InMicroseconds();
+ int64_t new_dt =
+ static_cast<int64_t>(static_cast<double>(old_dt) * scale);
+ time_before_expiration_ = base::TimeDelta::FromMicroseconds(new_dt);
+ Restart();
+}
+
const char* BaseNameFast(const char* file_name) {
// Case: Linux.
const char* end_pos = file_name + SbStringGetLength(file_name);
diff --git a/src/cobalt/browser/memory_tracker/tool/util.h b/src/cobalt/browser/memory_tracker/tool/util.h
index aa34660..02f2ca8 100644
--- a/src/cobalt/browser/memory_tracker/tool/util.h
+++ b/src/cobalt/browser/memory_tracker/tool/util.h
@@ -20,7 +20,11 @@
#include <string>
#include <vector>
+#include "base/callback.h"
+#include "base/logging.h"
#include "base/time.h"
+#include "starboard/string.h"
+#include "starboard/types.h"
namespace cobalt {
namespace browser {
@@ -71,13 +75,20 @@
// Simple timer class that fires periodically after dt time has elapsed.
class Timer {
public:
- explicit Timer(base::TimeDelta dt);
+ typedef base::Callback<base::TimeTicks(void)> TimeFunctor;
+
+ explicit Timer(base::TimeDelta delta_time);
+ Timer(base::TimeDelta delta_time, TimeFunctor f);
+
void Restart();
bool UpdateAndIsExpired(); // Returns true if the expiration was triggered.
+ void ScaleTimerAndReset(double scale);
private:
+ base::TimeTicks Now();
base::TimeTicks start_time_;
base::TimeDelta time_before_expiration_;
+ TimeFunctor time_function_override_;
};
struct AllocationSamples {
diff --git a/src/cobalt/browser/memory_tracker/tool/util_test.cc b/src/cobalt/browser/memory_tracker/tool/util_test.cc
index 07e9d63..988414d 100644
--- a/src/cobalt/browser/memory_tracker/tool/util_test.cc
+++ b/src/cobalt/browser/memory_tracker/tool/util_test.cc
@@ -18,16 +18,33 @@
#include <utility>
#include <vector>
+#include "base/bind.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace cobalt {
namespace browser {
namespace memory_tracker {
+namespace {
+
+class FakeTimeSource {
+ public:
+ explicit FakeTimeSource(base::TimeTicks value) : static_time_(value) {}
+ void set_static_time(base::TimeTicks value) {
+ static_time_ = value;
+ }
+ base::TimeTicks GetTime() {
+ return static_time_;
+ }
+ private:
+ base::TimeTicks static_time_;
+};
+
+} // namespace.
// Tests the expectation that AllocationSizeBinner will correctly bin
// allocations.
-TEST(MemoryTrackerUtilTest, RemoveString) {
+TEST(UtilTest, RemoveString) {
std::string value = "abba";
value = RemoveString(value, "bb");
EXPECT_STREQ("aa", value.c_str());
@@ -35,14 +52,14 @@
// Tests the expectation that AllocationSizeBinner will correctly bin
// allocations.
-TEST(MemoryTrackerUtilTest, InsertCommasIntoNumberString) {
+TEST(UtilTest, InsertCommasIntoNumberString) {
std::string value = "2345.54";
std::string value_with_commas = InsertCommasIntoNumberString(value);
EXPECT_STREQ("2,345.54", value_with_commas.c_str());
}
-TEST(MemoryTrackerUtilTest, NumberFormatWithCommas) {
+TEST(UtilTest, NumberFormatWithCommas) {
int value = 1000;
std::string value_with_commas = NumberFormatWithCommas<int>(value);
@@ -51,7 +68,7 @@
// Tests the expectation that RemoveOddElements() removes the odd elements of
// a vector and resizes it.
-TEST(MemoryTrackerUtilTest, RemoveOddElements) {
+TEST(UtilTest, RemoveOddElements) {
std::vector<int> values;
// EVEN TEST.
@@ -84,7 +101,7 @@
// Tests the expectation that GetLinearFit() generates the expected linear
// regression values.
-TEST(MemoryTrackerUtilTest, GetLinearFit) {
+TEST(UtilTest, GetLinearFit) {
std::vector<std::pair<int, int> > data;
for (int i = 0; i < 10; ++i) {
data.push_back(std::pair<int, int>(i+1, 2*i));
@@ -99,7 +116,7 @@
// Test the expectation that BaseNameFast() works correctly for both windows
// and linux path types.
-TEST(MemoryTrackerUtilTest, BaseNameFast) {
+TEST(UtilTest, BaseNameFast) {
const char* linux_path = "directory/filename.cc";
const char* win_path = "directory\\filename.cc";
@@ -107,6 +124,32 @@
EXPECT_STREQ("filename.cc", BaseNameFast(win_path));
}
+TEST(UtilTest, TimerUse) {
+ base::TimeTicks initial_time = base::TimeTicks::Now();
+ FakeTimeSource time_source(initial_time);
+
+ Timer::TimeFunctor time_functor =
+ base::Bind(&FakeTimeSource::GetTime, base::Unretained(&time_source));
+
+ Timer test_timer(base::TimeDelta::FromSeconds(30), time_functor);
+ EXPECT_FALSE(test_timer.UpdateAndIsExpired()); // 0 time has elapsed.
+
+ time_source.set_static_time(initial_time + base::TimeDelta::FromSeconds(29));
+ // 29 seconds has elapsed, which is less than the 30 seconds required for
+ // the timer to fire.
+ EXPECT_FALSE(test_timer.UpdateAndIsExpired());
+ time_source.set_static_time(initial_time + base::TimeDelta::FromSeconds(30));
+ // 31 seconds has elapsed, which means that the next call to
+ // UpdateAndIsExpired() should succeed.
+ EXPECT_TRUE(test_timer.UpdateAndIsExpired());
+ // Now that the value fired, expect that it won't fire again (until the next
+ // 30 seconds has passed).
+ EXPECT_FALSE(test_timer.UpdateAndIsExpired());
+ time_source.set_static_time(initial_time + base::TimeDelta::FromSeconds(60));
+ EXPECT_TRUE(test_timer.UpdateAndIsExpired());
+ EXPECT_FALSE(test_timer.UpdateAndIsExpired());
+}
+
} // namespace memory_tracker
} // namespace browser
} // namespace cobalt
diff --git a/src/cobalt/build/build.id b/src/cobalt/build/build.id
index c2eb52e..fcddd62 100644
--- a/src/cobalt/build/build.id
+++ b/src/cobalt/build/build.id
@@ -1 +1 @@
-55341
\ No newline at end of file
+56829
\ No newline at end of file
diff --git a/src/cobalt/build/config/base.gypi b/src/cobalt/build/config/base.gypi
index 0c93ea2..80b9306 100644
--- a/src/cobalt/build/config/base.gypi
+++ b/src/cobalt/build/config/base.gypi
@@ -438,7 +438,7 @@
# during system startup. To allocate a large chunk at startup helps with
# reducing frafmentation and can avoid failures to allocate incrementally.
# This can be set to 0.
- 'cobalt_media_buffer_initial_capacity%': 26 * 1024 * 1024,
+ 'cobalt_media_buffer_initial_capacity%': 0 * 1024 * 1024,
# When the media stack needs more memory to store media buffers, it will
# allocate extra memory in units of |cobalt_media_buffer_allocation_unit|.
# This can be set to 0, in which case the media stack will allocate extra
diff --git a/src/cobalt/cssom/cssom.gyp b/src/cobalt/cssom/cssom.gyp
index ecb8dad..08156e5 100644
--- a/src/cobalt/cssom/cssom.gyp
+++ b/src/cobalt/cssom/cssom.gyp
@@ -234,8 +234,15 @@
'url_value.cc',
'url_value.h',
],
+ 'export_dependent_settings': [
+ # Additionally, ensure that the include directories for generated
+ # headers are put on the include directories for targets that depend
+ # on this one.
+ '<(DEPTH)/cobalt/browser/browser_bindings_gen.gyp:generated_types',
+ ],
'dependencies': [
'<(DEPTH)/cobalt/base/base.gyp:base',
+ '<(DEPTH)/cobalt/browser/browser_bindings_gen.gyp:generated_types',
'<(DEPTH)/cobalt/dom/dom_exception.gyp:dom_exception',
'<(DEPTH)/cobalt/math/math.gyp:math',
'<(DEPTH)/googleurl/googleurl.gyp:googleurl',
diff --git a/src/cobalt/dom/document.cc b/src/cobalt/dom/document.cc
index 09a671c..32d5f9e 100644
--- a/src/cobalt/dom/document.cc
+++ b/src/cobalt/dom/document.cc
@@ -75,7 +75,9 @@
#if defined(ENABLE_PARTIAL_LAYOUT_CONTROL)
partial_layout_is_enabled_(true),
#endif // defined(ENABLE_PARTIAL_LAYOUT_CONTROL)
- navigation_start_clock_(options.navigation_start_clock),
+ navigation_start_clock_(options.navigation_start_clock
+ ? options.navigation_start_clock
+ : new base::SystemMonotonicClock()),
ALLOW_THIS_IN_INITIALIZER_LIST(
default_timeline_(new DocumentTimeline(this, 0))),
user_agent_style_sheet_(options.user_agent_style_sheet),
@@ -329,7 +331,11 @@
return NULL;
}
+// https://www.w3.org/TR/html5/editing.html#dom-document-activeelement
scoped_refptr<Element> Document::active_element() const {
+ // The activeElement attribute on Document objects must return the element in
+ // the document that is focused. If no element in the Document is focused,
+ // this must return the body element.
if (!active_element_) {
return body();
} else {
@@ -385,27 +391,11 @@
}
void Document::SetActiveElement(Element* active_element) {
- // Invalidate matching rules on old and new active element.
- if (active_element_) {
- HTMLElement* html_element = active_element_->AsHTMLElement();
- if (html_element) {
- html_element->InvalidateMatchingRulesRecursively();
- }
- }
if (active_element) {
- HTMLElement* html_element = active_element->AsHTMLElement();
- if (html_element) {
- html_element->InvalidateMatchingRulesRecursively();
- }
active_element_ = base::AsWeakPtr(active_element);
} else {
active_element_.reset();
}
-
- // Record mutation and trigger layout.
- is_computed_style_dirty_ = true;
- RecordMutation();
- FOR_EACH_OBSERVER(DocumentObserver, observers_, OnFocusChanged());
}
void Document::IncreaseLoadingCounter() { ++loading_counter_; }
@@ -461,6 +451,12 @@
csp_delegate_->NotifyUrlChanged(url);
}
+void Document::OnFocusChange() {
+ is_computed_style_dirty_ = true;
+ RecordMutation();
+ FOR_EACH_OBSERVER(DocumentObserver, observers_, OnFocusChanged());
+}
+
void Document::OnCSSMutation() {
// Something in the document's CSS rules has been modified, but we don't know
// what, so set the flag indicating that rule matching needs to be done.
@@ -594,6 +590,58 @@
}
}
+void Document::UpdateComputedStyleOnElementAndAncestor(HTMLElement* element) {
+ if (!element || element->node_document() != this ||
+ !is_computed_style_dirty_) {
+ return;
+ }
+
+ UpdateSelectorTree();
+ UpdateKeyframes();
+ UpdateFontFaces();
+
+ base::TimeDelta style_change_event_time =
+ base::TimeDelta::FromMillisecondsD(*default_timeline_->current_time());
+
+ // Find all ancestors of the element until the document.
+ std::vector<HTMLElement*> ancestors;
+ while (true) {
+ ancestors.push_back(element);
+ if (element->parent_node() == dynamic_cast<Node*>(this)) {
+ break;
+ }
+ Element* parent_element = element->parent_element();
+ if (!parent_element) {
+ return;
+ }
+ element = parent_element->AsHTMLElement();
+ if (!element) {
+ return;
+ }
+ }
+
+ // Update computed styles on the ancestors and the element.
+ HTMLElement* previous_element = NULL;
+ bool ancestors_were_valid = true;
+ for (std::vector<HTMLElement*>::reverse_iterator it = ancestors.rbegin();
+ it != ancestors.rend(); ++it) {
+ HTMLElement* current_element = *it;
+ bool is_valid = ancestors_were_valid &&
+ current_element->matching_rules_valid() &&
+ current_element->computed_style_valid();
+ if (!is_valid) {
+ DCHECK(initial_computed_style_declaration_);
+ DCHECK(initial_computed_style_data_);
+ current_element->UpdateComputedStyle(
+ previous_element ? previous_element->css_computed_style_declaration()
+ : initial_computed_style_declaration_,
+ initial_computed_style_data_, style_change_event_time);
+ }
+ previous_element = current_element;
+ ancestors_were_valid = is_valid;
+ }
+}
+
void Document::SampleTimelineTime() { default_timeline_->Sample(); }
#if defined(ENABLE_PARTIAL_LAYOUT_CONTROL)
diff --git a/src/cobalt/dom/document.h b/src/cobalt/dom/document.h
index 4e63114..fd9602c 100644
--- a/src/cobalt/dom/document.h
+++ b/src/cobalt/dom/document.h
@@ -246,6 +246,13 @@
return keyframes_map_;
}
+ // Returns whether the document has browsing context. Having the browsing
+ // context means the document is shown on the screen.
+ // https://www.w3.org/TR/html5/browsers.html#browsing-context
+ bool HasBrowsingContext() { return !!window_; }
+
+ void set_window(Window* window) { window_ = window; }
+
// Sets the active element of the document.
void SetActiveElement(Element* active_element);
@@ -265,6 +272,10 @@
// (see https://www.w3.org/TR/dom/#mutation-observers).
void RecordMutation();
+ // Called when the focus changes. This should be called only once when the
+ // focus is shifted from one element to another.
+ void OnFocusChange();
+
// From cssom::MutationObserver.
void OnCSSMutation() OVERRIDE;
@@ -281,6 +292,10 @@
// Matching rules, media rules, font faces and key frames are also updated.
void UpdateComputedStyles();
+ // Updates the computed styles of the element and all its ancestors.
+ // Matching rules, media rules, font faces and key frames are also updated.
+ void UpdateComputedStyleOnElementAndAncestor(HTMLElement* element);
+
// Manages the clock used by Web Animations.
// https://www.w3.org/TR/web-animations
// This clock is also used for requestAnimationFrame() callbacks, according
@@ -351,11 +366,6 @@
// Animations, using all the style sheets in the document.
void UpdateKeyframes();
- // Returns whether the document has browsing context. Having the browsing
- // context means the document is shown on the screen.
- // https://www.w3.org/TR/html5/browsers.html#browsing-context
- bool HasBrowsingContext() { return !!window_; }
-
// Reference to HTML element context.
HTMLElementContext* const html_element_context_;
// Reference to the associated window object.
diff --git a/src/cobalt/dom/dom.gyp b/src/cobalt/dom/dom.gyp
index 6738764..9e4437d 100644
--- a/src/cobalt/dom/dom.gyp
+++ b/src/cobalt/dom/dom.gyp
@@ -347,6 +347,7 @@
'testing/stub_css_parser.h',
'testing/stub_script_runner.cc',
'testing/stub_script_runner.h',
+ 'testing/stub_window.h',
],
'dependencies': [
# TODO: Remove the dependency below, it works around the fact that
diff --git a/src/cobalt/dom/dom_test.gyp b/src/cobalt/dom/dom_test.gyp
index 7ec5d03..9954088 100644
--- a/src/cobalt/dom/dom_test.gyp
+++ b/src/cobalt/dom/dom_test.gyp
@@ -69,6 +69,7 @@
],
'dependencies': [
'<(DEPTH)/cobalt/base/base.gyp:base',
+ '<(DEPTH)/cobalt/browser/browser.gyp:browser',
'<(DEPTH)/cobalt/css_parser/css_parser.gyp:css_parser',
'<(DEPTH)/cobalt/dom/dom.gyp:dom',
'<(DEPTH)/cobalt/dom/dom.gyp:dom_testing',
diff --git a/src/cobalt/dom/dom_token_list.cc b/src/cobalt/dom/dom_token_list.cc
index 0bc8b8e..31ab686 100644
--- a/src/cobalt/dom/dom_token_list.cc
+++ b/src/cobalt/dom/dom_token_list.cc
@@ -188,6 +188,10 @@
return tokens_;
}
+void DOMTokenList::TraceMembers(script::Tracer* tracer) {
+ tracer->Trace(element());
+}
+
DOMTokenList::~DOMTokenList() { GlobalStats::GetInstance()->Remove(this); }
// Algorithm for RunUpdateSteps:
diff --git a/src/cobalt/dom/dom_token_list.h b/src/cobalt/dom/dom_token_list.h
index 40e8a31..fb29a8c 100644
--- a/src/cobalt/dom/dom_token_list.h
+++ b/src/cobalt/dom/dom_token_list.h
@@ -55,6 +55,8 @@
// The associated element.
Element* element() { return element_; }
+ void TraceMembers(script::Tracer* tracer) OVERRIDE;
+
DEFINE_WRAPPABLE_TYPE(DOMTokenList);
private:
diff --git a/src/cobalt/dom/dom_token_list.idl b/src/cobalt/dom/dom_token_list.idl
index 721ba4e..66b16f6 100644
--- a/src/cobalt/dom/dom_token_list.idl
+++ b/src/cobalt/dom/dom_token_list.idl
@@ -14,7 +14,6 @@
// https://www.w3.org/TR/dom/#domtokenlist
-[AddOpaqueRoots=(element)]
interface DOMTokenList {
readonly attribute unsigned long length;
getter DOMString? item(unsigned long index);
diff --git a/src/cobalt/dom/eme/media_key_session.cc b/src/cobalt/dom/eme/media_key_session.cc
index f66bf48..5c62383 100644
--- a/src/cobalt/dom/eme/media_key_session.cc
+++ b/src/cobalt/dom/eme/media_key_session.cc
@@ -29,10 +29,11 @@
// See step 3.1 of
// https://www.w3.org/TR/encrypted-media/#dom-mediakeys-createsession.
MediaKeySession::MediaKeySession(
- scoped_ptr<media::DrmSystem::Session> drm_system_session,
+ const scoped_refptr<media::DrmSystem>& drm_system,
script::ScriptValueFactory* script_value_factory,
const ClosedCallback& closed_callback)
- : drm_system_session_(drm_system_session.Pass()),
+ : drm_system_(drm_system),
+ drm_system_session_(drm_system->CreateSession()),
script_value_factory_(script_value_factory),
uninitialized_(true),
callable_(false),
@@ -41,8 +42,9 @@
this, script_value_factory->CreateBasicPromise<void>())),
initiated_by_generate_request_(false) {}
-// Session ID should be empty for uninitialized sessions according to step 3.1
-// of https://www.w3.org/TR/encrypted-media/#dom-mediakeys-createsession.
+// According to the step 3.1 of
+// https://www.w3.org/TR/encrypted-media/#dom-mediakeys-createsession,
+// session ID should be empty until the first request is generated successfully.
std::string MediaKeySession::session_id() const {
return drm_system_session_->id().value_or("");
}
diff --git a/src/cobalt/dom/eme/media_key_session.h b/src/cobalt/dom/eme/media_key_session.h
index 4419362..cad6671 100644
--- a/src/cobalt/dom/eme/media_key_session.h
+++ b/src/cobalt/dom/eme/media_key_session.h
@@ -40,7 +40,7 @@
typedef base::Callback<void(MediaKeySession* session)> ClosedCallback;
// Custom, not in any spec.
- MediaKeySession(scoped_ptr<media::DrmSystem::Session> drm_system_session,
+ MediaKeySession(const scoped_refptr<media::DrmSystem>& drm_system,
script::ScriptValueFactory* script_value_factory,
const ClosedCallback& closed_callback);
@@ -68,6 +68,11 @@
void OnSessionDidNotUpdate(VoidPromiseValue::Reference* promise_reference);
void OnClosed();
+ // Although it doesn't make much sense, it's possible to call session methods
+ // when |MediaKeys| are destroyed. This behavior is underspecified but is
+ // consistent with Chromium. For this reason we need to hold to |drm_system_|
+ // from each session.
+ const scoped_refptr<media::DrmSystem> drm_system_;
scoped_ptr<media::DrmSystem::Session> drm_system_session_;
script::ScriptValueFactory* const script_value_factory_;
bool uninitialized_;
diff --git a/src/cobalt/dom/eme/media_keys.cc b/src/cobalt/dom/eme/media_keys.cc
index 861d44d..5a06fc4 100644
--- a/src/cobalt/dom/eme/media_keys.cc
+++ b/src/cobalt/dom/eme/media_keys.cc
@@ -38,9 +38,12 @@
}
// 3. Let session be a new MediaKeySession object.
+ //
+ // |MediaKeys| are passed to |MediaKeySession| as weak pointer because the
+ // order of destruction is not guaranteed due to JavaScript memory management.
scoped_refptr<MediaKeySession> session(new MediaKeySession(
- drm_system_->CreateSession(), script_value_factory_,
- base::Bind(&MediaKeys::OnSessionClosed, base::Unretained(this))));
+ drm_system_, script_value_factory_,
+ base::Bind(&MediaKeys::OnSessionClosed, AsWeakPtr())));
open_sessions_.push_back(session);
return session;
}
diff --git a/src/cobalt/dom/eme/media_keys.h b/src/cobalt/dom/eme/media_keys.h
index 52013df..5531904 100644
--- a/src/cobalt/dom/eme/media_keys.h
+++ b/src/cobalt/dom/eme/media_keys.h
@@ -19,7 +19,7 @@
#include <vector>
#include "base/memory/ref_counted.h"
-#include "base/memory/scoped_ptr.h"
+#include "base/memory/weak_ptr.h"
#include "cobalt/dom/buffer_source.h"
#include "cobalt/dom/eme/media_key_session.h"
#include "cobalt/dom/eme/media_key_session_type.h"
@@ -34,7 +34,8 @@
// Represents a set of keys that an associated HTMLMediaElement can use
// for decryption of media data during playback.
// https://www.w3.org/TR/encrypted-media/#mediakeys-interface
-class MediaKeys : public script::Wrappable {
+class MediaKeys : public script::Wrappable,
+ public base::SupportsWeakPtr<MediaKeys> {
public:
// Custom, not in any spec.
@@ -57,7 +58,7 @@
void OnSessionClosed(MediaKeySession* session);
script::ScriptValueFactory* script_value_factory_;
- scoped_ptr<media::DrmSystem> drm_system_;
+ scoped_refptr<media::DrmSystem> drm_system_;
// A MediaKeySession object shall not be destroyed and shall continue
// to receive events if it is not closed and the MediaKeys object that created
diff --git a/src/cobalt/dom/event.cc b/src/cobalt/dom/event.cc
index 3aac0af..2484c59 100644
--- a/src/cobalt/dom/event.cc
+++ b/src/cobalt/dom/event.cc
@@ -40,6 +40,23 @@
InitEventInternal(base::Token(type), false, false);
}
+Event::Event(base::Token type, const EventInit& eventInitDict)
+ : event_phase_(kNone),
+ time_stamp_(static_cast<uint64>(base::Time::Now().ToJsTime())) {
+ SB_DCHECK(eventInitDict.has_bubbles());
+ SB_DCHECK(eventInitDict.has_cancelable());
+ InitEventInternal(type, eventInitDict.bubbles(), eventInitDict.cancelable());
+}
+
+Event::Event(const std::string& type, const EventInit& eventInitDict)
+ : event_phase_(kNone),
+ time_stamp_(static_cast<uint64>(base::Time::Now().ToJsTime())) {
+ SB_DCHECK(eventInitDict.has_bubbles());
+ SB_DCHECK(eventInitDict.has_cancelable());
+ InitEventInternal(base::Token(type), eventInitDict.bubbles(),
+ eventInitDict.cancelable());
+}
+
Event::Event(base::Token type, Bubbles bubbles, Cancelable cancelable)
: event_phase_(kNone),
time_stamp_(static_cast<uint64>(base::Time::Now().ToJsTime())) {
@@ -59,6 +76,15 @@
}
void Event::InitEvent(const std::string& type, bool bubbles, bool cancelable) {
+ // Our event is for single use only.
+ DCHECK(!IsBeingDispatched());
+ DCHECK(!target());
+ DCHECK(!current_target());
+
+ if (IsBeingDispatched() || target() || current_target()) {
+ return;
+ }
+
InitEventInternal(base::Token(type), bubbles, cancelable);
}
@@ -71,15 +97,6 @@
}
void Event::InitEventInternal(base::Token type, bool bubbles, bool cancelable) {
- // Our event is for single use only.
- DCHECK(!IsBeingDispatched());
- DCHECK(!target());
- DCHECK(!current_target());
-
- if (IsBeingDispatched() || target() || current_target()) {
- return;
- }
-
type_ = type;
bubbles_ = bubbles;
cancelable_ = cancelable;
diff --git a/src/cobalt/dom/event.h b/src/cobalt/dom/event.h
index 97daeaa..090066d 100644
--- a/src/cobalt/dom/event.h
+++ b/src/cobalt/dom/event.h
@@ -19,6 +19,7 @@
#include "base/memory/weak_ptr.h"
#include "cobalt/base/token.h"
+#include "cobalt/dom/event_init.h"
#include "cobalt/script/wrappable.h"
namespace cobalt {
@@ -55,7 +56,10 @@
// Creates an event that cannot be bubbled and cancelled.
explicit Event(base::Token type);
explicit Event(const std::string& type);
+ Event(base::Token type, const EventInit& eventInitDict);
+ Event(const std::string& type, const EventInit& eventInitDict);
Event(base::Token type, Bubbles bubbles, Cancelable cancelable);
+
~Event() OVERRIDE;
// Web API: Event
diff --git a/src/cobalt/dom/event.idl b/src/cobalt/dom/event.idl
index a27e3e5..cd863e1 100644
--- a/src/cobalt/dom/event.idl
+++ b/src/cobalt/dom/event.idl
@@ -14,7 +14,7 @@
// https://www.w3.org/TR/dom/#event
-[Constructor(DOMString type)]
+[Constructor(DOMString type, optional EventInit eventInitDict)]
interface Event {
readonly attribute DOMString type;
readonly attribute EventTarget? target;
diff --git a/src/starboard/shared/win32/time_get_monotonic_thread_now.cc b/src/cobalt/dom/event_init.idl
similarity index 73%
rename from src/starboard/shared/win32/time_get_monotonic_thread_now.cc
rename to src/cobalt/dom/event_init.idl
index fff4bd9..f0974f5 100644
--- a/src/starboard/shared/win32/time_get_monotonic_thread_now.cc
+++ b/src/cobalt/dom/event_init.idl
@@ -12,10 +12,9 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-#include "starboard/time.h"
+// https://www.w3.org/TR/dom/#eventinit
-SbTimeMonotonic SbTimeGetMonotonicThreadNow() {
- // Neither QueryThreadCycleTime nor GetThreadTimes are listed as being
- // available in UWP.
- return SbTimeGetMonotonicNow();
-}
+dictionary EventInit {
+ boolean bubbles = false;
+ boolean cancelable = false;
+};
diff --git a/src/cobalt/dom/focus_event.cc b/src/cobalt/dom/focus_event.cc
index 69170ac..cacd086 100644
--- a/src/cobalt/dom/focus_event.cc
+++ b/src/cobalt/dom/focus_event.cc
@@ -24,5 +24,9 @@
const scoped_refptr<EventTarget>& related_target)
: UIEvent(type), related_target_(related_target) {}
+FocusEvent::FocusEvent(base::Token type, Bubbles bubbles, Cancelable cancelable,
+ const scoped_refptr<EventTarget>& related_target)
+ : UIEvent(type, bubbles, cancelable), related_target_(related_target) {}
+
} // namespace dom
} // namespace cobalt
diff --git a/src/cobalt/dom/focus_event.h b/src/cobalt/dom/focus_event.h
index a6727c1..57ba8a3 100644
--- a/src/cobalt/dom/focus_event.h
+++ b/src/cobalt/dom/focus_event.h
@@ -34,6 +34,9 @@
FocusEvent(base::Token type,
const scoped_refptr<EventTarget>& related_target);
+ FocusEvent(base::Token type, Bubbles bubbles, Cancelable cancelable,
+ const scoped_refptr<EventTarget>& related_target);
+
// Web API: FocusEvent
//
const scoped_refptr<EventTarget>& related_target() const {
diff --git a/src/cobalt/dom/html_element.cc b/src/cobalt/dom/html_element.cc
index e1e9485..af05c42 100644
--- a/src/cobalt/dom/html_element.cc
+++ b/src/cobalt/dom/html_element.cc
@@ -191,33 +191,42 @@
SetAttribute("tabindex", base::Int32ToString(tab_index));
}
+// Algorithm for Focus:
+// https://www.w3.org/TR/html5/editing.html#dom-focus
void HTMLElement::Focus() {
- if (!IsFocusable()) {
+ // 1. If the element is marked as locked for focus, then abort these steps.
+ if (locked_for_focus_) {
return;
}
+ // 2. Mark the element as locked for focus.
+ locked_for_focus_ = true;
+
+ // 3. Run the focusing steps for the element.
+ RunFocusingSteps();
+
+ // 4. Unmark the element as locked for focus.
+ locked_for_focus_ = false;
+
+ // Custom, not in any spec.
Document* document = node_document();
- Element* old_active_element = document->active_element();
- if (old_active_element == this->AsElement()) {
- return;
+ if (document) {
+ document->OnFocusChange();
}
-
- document->SetActiveElement(this);
-
- if (old_active_element) {
- old_active_element->DispatchEvent(
- new FocusEvent(base::Tokens::blur(), this));
- }
-
- DispatchEvent(new FocusEvent(base::Tokens::focus(), old_active_element));
}
+// Algorithm for Blur:
+// https://www.w3.org/TR/html5/editing.html#dom-blur
void HTMLElement::Blur() {
- Document* document = node_document();
- if (document->active_element() == this->AsElement()) {
- document->SetActiveElement(NULL);
+ // The blur() method, when invoked, should run the unfocusing steps for the
+ // element on which the method was called instead. User agents may selectively
+ // or uniformly ignore calls to this method for usability reasons.
+ RunUnFocusingSteps();
- DispatchEvent(new FocusEvent(base::Tokens::blur(), NULL));
+ // Custom, not in any spec.
+ Document* document = node_document();
+ if (document) {
+ document->OnFocusChange();
}
}
@@ -519,6 +528,7 @@
void HTMLElement::OnCSSMutation() {
// Invalidate the computed style of this node.
computed_style_valid_ = false;
+ descendant_computed_styles_valid_ = false;
// Remove the style attribute value from the Element.
Element::RemoveStyleAttribute();
@@ -650,16 +660,23 @@
return;
}
- // Update computed style for this element's descendants.
+ // Update computed style for this element's descendants. Note that if
+ // descendant_computed_styles_valid_ flag is not set, the ancestors should
+ // still be considered invalid, which forces the computes styles to be updated
+ // on all children.
for (Element* element = first_element_child(); element;
element = element->next_element_sibling()) {
HTMLElement* html_element = element->AsHTMLElement();
if (html_element) {
html_element->UpdateComputedStyleRecursively(
css_computed_style_declaration(), root_computed_style,
- style_change_event_time, is_valid, current_element_depth + 1);
+ style_change_event_time,
+ is_valid && descendant_computed_styles_valid_,
+ current_element_depth + 1);
}
}
+
+ descendant_computed_styles_valid_ = true;
}
void HTMLElement::PurgeCachedBackgroundImagesOfNodeAndDescendants() {
@@ -667,12 +684,14 @@
if (!cached_background_images_.empty()) {
cached_background_images_.clear();
computed_style_valid_ = false;
+ descendant_computed_styles_valid_ = false;
}
PurgeCachedBackgroundImagesOfDescendants();
}
void HTMLElement::InvalidateComputedStylesOfNodeAndDescendants() {
computed_style_valid_ = false;
+ descendant_computed_styles_valid_ = false;
InvalidateComputedStylesOfDescendants();
}
@@ -707,10 +726,12 @@
HTMLElement::HTMLElement(Document* document, base::Token local_name)
: Element(document, local_name),
dom_stat_tracker_(document->html_element_context()->dom_stat_tracker()),
+ locked_for_focus_(false),
directionality_(kNoExplicitDirectionality),
style_(new cssom::CSSDeclaredStyleDeclaration(
document->html_element_context()->css_parser())),
computed_style_valid_(false),
+ descendant_computed_styles_valid_(false),
css_computed_style_declaration_(new cssom::CSSComputedStyleDeclaration()),
ALLOW_THIS_IN_INITIALIZER_LIST(
transitions_adapter_(new DOMAnimatable(this))),
@@ -739,6 +760,25 @@
void HTMLElement::OnMutation() { InvalidateMatchingRulesRecursively(); }
+void HTMLElement::OnRemovedFromDocument() {
+ Node::OnRemovedFromDocument();
+
+ // When an element that is focused stops being a focusable element, or stops
+ // being focused without another element being explicitly focused in its
+ // stead, the user agent should synchronously run the unfocusing steps for the
+ // affected element only.
+ // For example, this might happen because the element is removed from its
+ // Document, or has a hidden attribute added. It would also happen to an input
+ // element when the element gets disabled.
+ // https://www.w3.org/TR/html5/editing.html#unfocusing-steps
+ Document* document = node_document();
+ DCHECK(document);
+ if (document->active_element() == this->AsElement()) {
+ RunUnFocusingSteps();
+ document->OnFocusChange();
+ }
+}
+
void HTMLElement::OnSetAttribute(const std::string& name,
const std::string& value) {
if (name == "class" || name == "id") {
@@ -756,6 +796,117 @@
}
}
+// Algorithm for IsFocusable:
+// https://www.w3.org/TR/html5/editing.html#focusable
+bool HTMLElement::IsFocusable() {
+ return HasTabindexFocusFlag() && IsBeingRendered();
+}
+
+// Algorithm for HasTabindexFocusFlag:
+// https://www.w3.org/TR/html5/editing.html#specially-focusable
+bool HTMLElement::HasTabindexFocusFlag() const {
+ int32 tabindex;
+ return base::StringToInt32(GetAttribute("tabindex").value_or(""), &tabindex);
+}
+
+// An element is being rendered if it has any associated CSS layout boxes, SVG
+// layout boxes, or some equivalent in other styling languages.
+// https://www.w3.org/TR/html5/rendering.html#being-rendered
+bool HTMLElement::IsBeingRendered() {
+ Document* document = node_document();
+ if (!document) {
+ return false;
+ }
+
+ document->UpdateComputedStyleOnElementAndAncestor(this);
+
+ return computed_style()->display() != cssom::KeywordValue::GetNone() &&
+ computed_style()->visibility() == cssom::KeywordValue::GetVisible();
+}
+
+// Algorithm for RunFocusingSteps:
+// https://www.w3.org/TR/html5/editing.html#focusing-steps
+void HTMLElement::RunFocusingSteps() {
+ // 1. If the element is not in a Document, or if the element's Document has
+ // no browsing context, or if the element's Document's browsing context has no
+ // top-level browsing context, or if the element is not focusable, or if the
+ // element is already focused, then abort these steps.
+ Document* document = node_document();
+ if (!document || !document->HasBrowsingContext() || !IsFocusable()) {
+ return;
+ }
+ Element* old_active_element = document->active_element();
+ if (old_active_element == this) {
+ return;
+ }
+
+ // 2. If focusing the element will remove the focus from another element,
+ // then run the unfocusing steps for that element.
+ if (old_active_element && old_active_element->AsHTMLElement()) {
+ old_active_element->AsHTMLElement()->RunUnFocusingSteps();
+ }
+
+ // focusin: A user agent MUST dispatch this event when an event target is
+ // about to receive focus. This event type MUST be dispatched before the
+ // element is given focus. The event target MUST be the element which is about
+ // to receive focus. This event type is similar to focus, but is dispatched
+ // before focus is shifted, and does bubble.
+ // https://www.w3.org/TR/2016/WD-uievents-20160804/#event-type-focusin
+ DispatchEvent(new FocusEvent(base::Tokens::focusin(), Event::kBubbles,
+ Event::kNotCancelable, this));
+
+ // 3. Make the element the currently focused element in its top-level browsing
+ // context.
+ document->SetActiveElement(this);
+
+ // 4. Not needed by Cobalt.
+
+ // 5. Fire a simple event named focus at the element.
+ // focus: A user agent MUST dispatch this event when an event target receives
+ // focus. The focus MUST be given to the element before the dispatch of this
+ // event type. This event type is similar to focusin, but is dispatched after
+ // focus is shifted, and does not bubble.
+ // https://www.w3.org/TR/2016/WD-uievents-20160804/#event-type-focus
+ DispatchEvent(new FocusEvent(base::Tokens::focus(), Event::kNotBubbles,
+ Event::kNotCancelable, this));
+
+ // Custom, not in any sepc.
+ InvalidateMatchingRulesRecursively();
+}
+
+// Algorithm for RunUnFocusingSteps:
+// https://www.w3.org/TR/html5/editing.html#unfocusing-steps
+void HTMLElement::RunUnFocusingSteps() {
+ // 1. Not needed by Cobalt.
+
+ // focusout: A user agent MUST dispatch this event when an event target is
+ // about to lose focus. This event type MUST be dispatched before the element
+ // loses focus. The event target MUST be the element which is about to lose
+ // focus. This event type is similar to blur, but is dispatched before focus
+ // is shifted, and does bubble.
+ // https://www.w3.org/TR/2016/WD-uievents-20160804/#event-type-focusout
+ DispatchEvent(new FocusEvent(base::Tokens::focusout(), Event::kBubbles,
+ Event::kNotCancelable, this));
+
+ // 2. Unfocus the element.
+ Document* document = node_document();
+ if (document && document->active_element() == this->AsElement()) {
+ document->SetActiveElement(NULL);
+ }
+
+ // 3. Fire a simple event named blur at the element.
+ // blur: A user agent MUST dispatch this event when an event target loses
+ // focus. The focus MUST be taken from the element before the dispatch of this
+ // event type. This event type is similar to focusout, but is dispatched after
+ // focus is shifted, and does not bubble.
+ // https://www.w3.org/TR/2016/WD-uievents-20160804/#event-type-blur
+ DispatchEvent(new FocusEvent(base::Tokens::blur(), Event::kNotBubbles,
+ Event::kNotCancelable, this));
+
+ // Custom, not in any sepc.
+ InvalidateMatchingRulesRecursively();
+}
+
void HTMLElement::SetDirectionality(const std::string& value) {
// NOTE: Value "auto" is not supported.
Directionality previous_directionality = directionality_;
diff --git a/src/cobalt/dom/html_element.h b/src/cobalt/dom/html_element.h
index 88bbccd..42c0146 100644
--- a/src/cobalt/dom/html_element.h
+++ b/src/cobalt/dom/html_element.h
@@ -219,6 +219,15 @@
root_computed_style,
const base::TimeDelta& style_change_event_time, bool ancestors_were_valid,
int current_element_depth);
+
+ // Updates the cached computed style of this element and its anecstors.
+ void UpdateComputedStyleAlongAncestors(
+ const scoped_refptr<cssom::CSSComputedStyleDeclaration>&
+ parent_computed_style,
+ const scoped_refptr<const cssom::CSSComputedStyleData>&
+ root_computed_style,
+ const base::TimeDelta& style_change_event_time);
+
// Updates the cached computed style of this element.
void UpdateComputedStyle(
const scoped_refptr<cssom::CSSComputedStyleDeclaration>&
@@ -238,9 +247,6 @@
LayoutBoxes* layout_boxes() const { return layout_boxes_.get(); }
- // Determines whether this element is focusable.
- bool IsFocusable() const { return HasAttribute("tabindex"); }
-
PseudoElement* pseudo_element(PseudoElementType type) const {
DCHECK(type < kMaxPseudoElementType);
return pseudo_elements_[type].get();
@@ -253,6 +259,10 @@
pseudo_elements_[type] = pseudo_element.Pass();
}
+ bool computed_style_valid() const { return computed_style_valid_; }
+
+ bool matching_rules_valid() const { return matching_rules_valid_; }
+
DEFINE_WRAPPABLE_TYPE(HTMLElement);
protected:
@@ -269,12 +279,20 @@
private:
// From Node.
void OnMutation() OVERRIDE;
+ void OnRemovedFromDocument() OVERRIDE;
// From Element.
void OnSetAttribute(const std::string& name,
const std::string& value) OVERRIDE;
void OnRemoveAttribute(const std::string& name) OVERRIDE;
+ bool IsFocusable();
+ bool HasTabindexFocusFlag() const;
+ bool IsBeingRendered();
+
+ void RunFocusingSteps();
+ void RunUnFocusingSteps();
+
// This both updates the directionality based upon the string value and
// invalidates layout box caching if the value has changed.
// NOTE1: Value "auto" is not supported.
@@ -298,6 +316,8 @@
// https://www.w3.org/TR/html5/semantics.html#the-root-element.
bool IsRootElement();
+ bool locked_for_focus_;
+
// The directionality of the html element is determined by the 'dir'
// attribute.
// https://dev.w3.org/html5/spec-preview/global-attributes.html#the-directionality
@@ -315,6 +335,9 @@
// Keeps track of whether the HTML element's current computed style is out
// of date or not.
bool computed_style_valid_;
+ // Keeps track of whether the HTML element's descendants' computed styles are
+ // out of date or not.
+ bool descendant_computed_styles_valid_;
scoped_refptr<cssom::CSSComputedStyleDeclaration>
css_computed_style_declaration_;
diff --git a/src/cobalt/dom/html_element_test.cc b/src/cobalt/dom/html_element_test.cc
index 685ccab..239d247 100644
--- a/src/cobalt/dom/html_element_test.cc
+++ b/src/cobalt/dom/html_element_test.cc
@@ -30,6 +30,11 @@
#include "cobalt/dom/html_element_context.h"
#include "cobalt/dom/layout_boxes.h"
#include "cobalt/dom/named_node_map.h"
+#include "cobalt/dom/testing/stub_window.h"
+#include "cobalt/dom/window.h"
+#include "cobalt/media_session/media_session.h"
+#include "cobalt/network_bridge/net_poster.h"
+#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
using ::testing::Return;
@@ -59,10 +64,10 @@
const char kFooBarDeclarationString[] = "foo: bar;";
const char kDisplayInlineDeclarationString[] = "display: inline;";
-class MockLayoutBoxes : public dom::LayoutBoxes {
+class MockLayoutBoxes : public LayoutBoxes {
public:
MOCK_CONST_METHOD0(type, Type());
- MOCK_CONST_METHOD0(GetClientRects, scoped_refptr<dom::DOMRectList>());
+ MOCK_CONST_METHOD0(GetClientRects, scoped_refptr<DOMRectList>());
MOCK_CONST_METHOD0(IsInlineLevel, bool());
@@ -122,7 +127,6 @@
scoped_ptr<DomStatTracker> dom_stat_tracker_;
HTMLElementContext html_element_context_;
scoped_refptr<Document> document_;
- MessageLoop message_loop_;
};
scoped_refptr<HTMLElement>
@@ -142,8 +146,7 @@
if (parent_html_element) {
// Set layout boxes for all elements that have a child.
scoped_ptr<MockLayoutBoxes> layout_boxes(new MockLayoutBoxes);
- parent_html_element->set_layout_boxes(
- layout_boxes.PassAs<dom::LayoutBoxes>());
+ parent_html_element->set_layout_boxes(layout_boxes.PassAs<LayoutBoxes>());
parent_html_element->AppendChild(child_html_element);
}
@@ -162,7 +165,7 @@
if (child_element) {
scoped_ptr<MockLayoutBoxes> layout_boxes(new MockLayoutBoxes);
parent_element->AsHTMLElement()->set_layout_boxes(
- layout_boxes.PassAs<dom::LayoutBoxes>());
+ layout_boxes.PassAs<LayoutBoxes>());
}
parent_element = child_element;
}
@@ -199,26 +202,72 @@
EXPECT_EQ(-1, html_element->tab_index());
}
-TEST_F(HTMLElementTest, FocusBlur) {
+TEST_F(HTMLElementTest, Focus) {
+ // Give the document browsing context which is needed for focus to work.
+ testing::StubWindow window;
+ document_->set_window(window.window());
+ // Give the document initial computed style.
+ document_->SetViewport(math::Size(320, 240));
+
+ scoped_refptr<HTMLElement> html_element_1 =
+ document_->CreateElement("div")->AsHTMLElement();
+ scoped_refptr<HTMLElement> html_element_2 =
+ document_->CreateElement("div")->AsHTMLElement();
+ document_->AppendChild(html_element_1);
+ document_->AppendChild(html_element_2);
+ EXPECT_FALSE(document_->active_element());
+
+ html_element_1->set_tab_index(-1);
+ html_element_1->Focus();
+ ASSERT_TRUE(document_->active_element());
+ EXPECT_EQ(html_element_1, document_->active_element()->AsHTMLElement());
+
+ html_element_2->set_tab_index(-1);
+ html_element_2->Focus();
+ ASSERT_TRUE(document_->active_element());
+ EXPECT_EQ(html_element_2, document_->active_element()->AsHTMLElement());
+}
+
+TEST_F(HTMLElementTest, Blur) {
+ // Give the document browsing context which is needed for focus to work.
+ testing::StubWindow window;
+ document_->set_window(window.window());
+ // Give the document initial computed style.
+ document_->SetViewport(math::Size(320, 240));
+
scoped_refptr<HTMLElement> html_element =
document_->CreateElement("div")->AsHTMLElement();
+ document_->AppendChild(html_element);
EXPECT_FALSE(document_->active_element());
html_element->set_tab_index(-1);
html_element->Focus();
+ ASSERT_TRUE(document_->active_element());
EXPECT_EQ(html_element, document_->active_element()->AsHTMLElement());
html_element->Blur();
EXPECT_FALSE(document_->active_element());
}
-TEST_F(HTMLElementTest, IsFocusable) {
+TEST_F(HTMLElementTest, RemoveActiveElementShouldRunBlur) {
+ // Give the document browsing context which is needed for focus to work.
+ testing::StubWindow window;
+ document_->set_window(window.window());
+ // Give the document initial computed style.
+ document_->SetViewport(math::Size(320, 240));
+
scoped_refptr<HTMLElement> html_element =
document_->CreateElement("div")->AsHTMLElement();
- EXPECT_FALSE(html_element->IsFocusable());
+ document_->AppendChild(html_element);
+ EXPECT_FALSE(document_->active_element());
html_element->set_tab_index(-1);
- EXPECT_TRUE(html_element->IsFocusable());
+ html_element->Focus();
+ ASSERT_TRUE(document_->active_element());
+ EXPECT_EQ(html_element, document_->active_element()->AsHTMLElement());
+
+ document_->RemoveChild(html_element);
+ EXPECT_FALSE(document_->active_element());
}
TEST_F(HTMLElementTest, LayoutBoxesGetter) {
@@ -227,16 +276,16 @@
scoped_ptr<MockLayoutBoxes> mock_layout_boxes(new MockLayoutBoxes);
MockLayoutBoxes* saved_mock_layout_boxes_ptr = mock_layout_boxes.get();
- html_element->set_layout_boxes(mock_layout_boxes.PassAs<dom::LayoutBoxes>());
+ html_element->set_layout_boxes(mock_layout_boxes.PassAs<LayoutBoxes>());
DCHECK(mock_layout_boxes.get() == NULL);
EXPECT_CALL(*base::polymorphic_downcast<MockLayoutBoxes*>(
html_element->layout_boxes()),
type())
- .WillOnce(Return(dom::LayoutBoxes::kLayoutLayoutBoxes));
- dom::LayoutBoxes* layout_boxes = html_element->layout_boxes();
+ .WillOnce(Return(LayoutBoxes::kLayoutLayoutBoxes));
+ LayoutBoxes* layout_boxes = html_element->layout_boxes();
EXPECT_EQ(layout_boxes, saved_mock_layout_boxes_ptr);
- EXPECT_EQ(layout_boxes->type(), dom::LayoutBoxes::kLayoutLayoutBoxes);
+ EXPECT_EQ(layout_boxes->type(), LayoutBoxes::kLayoutLayoutBoxes);
}
TEST_F(HTMLElementTest, GetBoundingClientRectWithoutLayoutBox) {
@@ -264,7 +313,7 @@
EXPECT_FLOAT_EQ(html_element->client_top(), 0.0f);
scoped_ptr<MockLayoutBoxes> layout_boxes(new MockLayoutBoxes);
- html_element->set_layout_boxes(layout_boxes.PassAs<dom::LayoutBoxes>());
+ html_element->set_layout_boxes(layout_boxes.PassAs<LayoutBoxes>());
// 1. If the CSS layout box is inline, return zero.
EXPECT_CALL(*base::polymorphic_downcast<MockLayoutBoxes*>(
@@ -298,7 +347,7 @@
EXPECT_FLOAT_EQ(html_element->client_left(), 0.0f);
scoped_ptr<MockLayoutBoxes> layout_boxes(new MockLayoutBoxes);
- html_element->set_layout_boxes(layout_boxes.PassAs<dom::LayoutBoxes>());
+ html_element->set_layout_boxes(layout_boxes.PassAs<LayoutBoxes>());
// 1. If the CSS layout box is inline, return zero.
EXPECT_CALL(*base::polymorphic_downcast<MockLayoutBoxes*>(
@@ -582,7 +631,7 @@
EXPECT_FLOAT_EQ(html_element->offset_width(), 0.0f);
scoped_ptr<MockLayoutBoxes> layout_boxes(new MockLayoutBoxes);
- html_element->set_layout_boxes(layout_boxes.PassAs<dom::LayoutBoxes>());
+ html_element->set_layout_boxes(layout_boxes.PassAs<LayoutBoxes>());
// 2. Return the border edge width of the first CSS layout box associated with
// the element, ignoring any transforms that apply to the element and its
@@ -605,7 +654,7 @@
EXPECT_FLOAT_EQ(html_element->offset_height(), 0.0f);
scoped_ptr<MockLayoutBoxes> layout_boxes(new MockLayoutBoxes);
- html_element->set_layout_boxes(layout_boxes.PassAs<dom::LayoutBoxes>());
+ html_element->set_layout_boxes(layout_boxes.PassAs<LayoutBoxes>());
// 2. Return the border edge height of the first CSS layout box associated
// with the element, ignoring any transforms that apply to the element and its
diff --git a/src/cobalt/dom/html_media_element.cc b/src/cobalt/dom/html_media_element.cc
index 869d4c2..51edf3e 100644
--- a/src/cobalt/dom/html_media_element.cc
+++ b/src/cobalt/dom/html_media_element.cc
@@ -776,8 +776,7 @@
ScheduleOwnEvent(base::Tokens::abort());
}
- ClearMediaSource();
-
+ ClearMediaPlayer();
CreateMediaPlayer();
// 4 - If the media element's networkState is not set to kNetworkEmpty, then
diff --git a/src/cobalt/dom/navigator.cc b/src/cobalt/dom/navigator.cc
index b567262..ebbb42d 100644
--- a/src/cobalt/dom/navigator.cc
+++ b/src/cobalt/dom/navigator.cc
@@ -14,12 +14,14 @@
#include "cobalt/dom/navigator.h"
+#include "base/optional.h"
#include "cobalt/dom/dom_exception.h"
#if defined(COBALT_MEDIA_SOURCE_2016)
#include "cobalt/dom/eme/media_key_system_access.h"
#endif // defined(COBALT_MEDIA_SOURCE_2016)
#include "cobalt/media_session/media_session_client.h"
#include "cobalt/script/script_value_factory.h"
+#include "starboard/media.h"
using cobalt::media_session::MediaSession;
@@ -61,15 +63,137 @@
namespace {
-// TODO: Implement "3.1.1.1 Get Supported Configuration" using
-// SbMediaCanPlayMimeAndKeySystem().
-// https://www.w3.org/TR/encrypted-media/#get-supported-configuration
-bool MaybeGetSupportedConfiguration(
- const std::string& /*key_system*/,
- const eme::MediaKeySystemConfiguration& candidate_configuration,
- eme::MediaKeySystemConfiguration* supported_configuration) {
- *supported_configuration = candidate_configuration;
- return true;
+// See
+// https://www.w3.org/TR/encrypted-media/#get-supported-capabilities-for-audio-video-type.
+base::optional<script::Sequence<MediaKeySystemMediaCapability> >
+TryGetSupportedCapabilities(
+ const std::string& key_system,
+ const script::Sequence<MediaKeySystemMediaCapability>&
+ requested_media_capabilities) {
+ // 2. Let supported media capabilities be an empty sequence of
+ // MediaKeySystemMediaCapability dictionaries.
+ script::Sequence<MediaKeySystemMediaCapability> supported_media_capabilities;
+ // 3. For each requested media capability in requested media capabilities:
+ for (std::size_t media_capability_index = 0;
+ media_capability_index < requested_media_capabilities.size();
+ ++media_capability_index) {
+ const MediaKeySystemMediaCapability& requested_media_capability =
+ requested_media_capabilities.at(media_capability_index);
+ // 3.1. Let content type be requested media capability's contentType member.
+ const std::string& content_type = requested_media_capability.content_type();
+ // 3.3. If content type is the empty string, return null.
+ if (content_type.empty()) {
+ return base::nullopt;
+ }
+ // 3.13. If the user agent and [CDM] implementation definitely support
+ // playback of encrypted media data for the combination of container,
+ // media types [...]:
+ if (SbMediaCanPlayMimeAndKeySystem(content_type.c_str(),
+ key_system.c_str()) ==
+ kSbMediaSupportTypeProbably) {
+ // 3.13.1. Add requested media capability to supported media capabilities.
+ supported_media_capabilities.push_back(requested_media_capability);
+ }
+ }
+ // 4. If supported media capabilities is empty, return null.
+ if (supported_media_capabilities.empty()) {
+ return base::nullopt;
+ }
+ // 5. Return supported media capabilities.
+ return supported_media_capabilities;
+}
+
+// Technically, a user agent is supposed to implement "3.1.1.1 Get Supported
+// Configuration" which requests the user consent until it's given. But since
+// Cobalt never interacts with the user directly, we'll assume that the consent
+// is always given and go straight to "3.1.1.2 Get Supported Configuration and
+// Consent". See
+// https://www.w3.org/TR/encrypted-media/#get-supported-configuration-and-consent.
+base::optional<eme::MediaKeySystemConfiguration> TryGetSupportedConfiguration(
+ const std::string& key_system,
+ const eme::MediaKeySystemConfiguration& candidate_configuration) {
+ // 1. Let accumulated configuration be a new MediaKeySystemConfiguration
+ // dictionary.
+ eme::MediaKeySystemConfiguration accumulated_configuration;
+
+ // 2. Set the label member of accumulated configuration to equal the label
+ // member of candidate configuration.
+ accumulated_configuration.set_label(candidate_configuration.label());
+
+ // For now, copy initialization data types into accumulated configuration.
+ //
+ // TODO: Implement step 3 after introducing a Starboard API for detecting
+ // supported initialization data type.
+ // TODO: Checking has_init_data_types() won't be needed once Cobalt supports
+ // default values for IDL sequences.
+ accumulated_configuration.set_init_data_types(
+ candidate_configuration.has_init_data_types()
+ ? candidate_configuration.init_data_types()
+ : script::Sequence<std::string>());
+
+ // TODO: Reject distinctive identifiers, persistent state, and persistent
+ // sessions.
+
+ // 15. If the videoCapabilities and audioCapabilities members in candidate
+ // configuration are both empty, return NotSupported.
+ //
+ // TODO: Checking has_video_capabilities() and has_audio_capabilities() won't
+ // be needed once Cobalt supports default values for IDL sequences.
+ if ((!candidate_configuration.has_video_capabilities() ||
+ candidate_configuration.video_capabilities().empty()) &&
+ (!candidate_configuration.has_audio_capabilities() ||
+ candidate_configuration.audio_capabilities().empty())) {
+ return base::nullopt;
+ }
+
+ // 16. If the videoCapabilities member in candidate configuration is
+ // non-empty:
+ if (candidate_configuration.has_video_capabilities() &&
+ !candidate_configuration.video_capabilities().empty()) {
+ // 16.1. Let video capabilities be the result of executing the "Get
+ // Supported Capabilities for Audio/Video Type" algorithm.
+ base::optional<script::Sequence<MediaKeySystemMediaCapability> >
+ maybe_video_capabilities = TryGetSupportedCapabilities(
+ key_system, candidate_configuration.video_capabilities());
+ // 16.2. If video capabilities is null, return NotSupported.
+ if (!maybe_video_capabilities) {
+ return base::nullopt;
+ }
+ // 16.3. Set the videoCapabilities member of accumulated configuration to
+ // video capabilities.
+ accumulated_configuration.set_video_capabilities(*maybe_video_capabilities);
+ } else {
+ // Otherwise: set the videoCapabilities member of accumulated configuration
+ // to an empty sequence.
+ accumulated_configuration.set_video_capabilities(
+ script::Sequence<MediaKeySystemMediaCapability>());
+ }
+
+ // 17. If the audioCapabilities member in candidate configuration is
+ // non-empty:
+ if (candidate_configuration.has_audio_capabilities() &&
+ !candidate_configuration.audio_capabilities().empty()) {
+ // 17.1. Let audio capabilities be the result of executing the "Get
+ // Supported Capabilities for Audio/Video Type" algorithm.
+ base::optional<script::Sequence<MediaKeySystemMediaCapability> >
+ maybe_audio_capabilities = TryGetSupportedCapabilities(
+ key_system, candidate_configuration.audio_capabilities());
+ // 17.2. If audio capabilities is null, return NotSupported.
+ if (!maybe_audio_capabilities) {
+ return base::nullopt;
+ }
+ // 17.3. Set the audioCapabilities member of accumulated configuration to
+ // audio capabilities.
+ accumulated_configuration.set_audio_capabilities(*maybe_audio_capabilities);
+ } else {
+ // Otherwise: set the audioCapabilities member of accumulated configuration
+ // to an empty sequence.
+ accumulated_configuration.set_audio_capabilities(
+ script::Sequence<MediaKeySystemMediaCapability>());
+ }
+
+ // 23. Return accumulated configuration.
+ return accumulated_configuration;
}
} // namespace
@@ -96,17 +220,18 @@
}
// 6.3. For each value in |supportedConfigurations|:
- for (size_t configuration_index = 0;
+ for (std::size_t configuration_index = 0;
configuration_index < supported_configurations.size();
++configuration_index) {
// 6.3.3. If supported configuration is not NotSupported:
- eme::MediaKeySystemConfiguration supported_configuration;
- if (MaybeGetSupportedConfiguration(
- key_system, supported_configurations.at(configuration_index),
- &supported_configuration)) {
+ base::optional<eme::MediaKeySystemConfiguration>
+ maybe_supported_configuration = TryGetSupportedConfiguration(
+ key_system, supported_configurations.at(configuration_index));
+ if (maybe_supported_configuration) {
// 6.3.3.1. Let access be a new MediaKeySystemAccess object.
scoped_refptr<eme::MediaKeySystemAccess> media_key_system_access(
- new eme::MediaKeySystemAccess(key_system, supported_configuration,
+ new eme::MediaKeySystemAccess(key_system,
+ *maybe_supported_configuration,
script_value_factory_));
// 6.3.3.2. Resolve promise.
promise_reference.value().Resolve(media_key_system_access);
diff --git a/src/cobalt/dom/node.idl b/src/cobalt/dom/node.idl
index 7649487..e1d2ec1 100644
--- a/src/cobalt/dom/node.idl
+++ b/src/cobalt/dom/node.idl
@@ -14,10 +14,6 @@
// https://www.w3.org/TR/dom/#node
-[
- GetOpaqueRoot=GetRootNode,
- AddOpaqueRoots=(GetRootNode),
-]
interface Node : EventTarget {
const unsigned short ELEMENT_NODE = 1;
const unsigned short TEXT_NODE = 3;
diff --git a/src/cobalt/dom/rule_matching_test.cc b/src/cobalt/dom/rule_matching_test.cc
index e7ef524..5323f3d 100644
--- a/src/cobalt/dom/rule_matching_test.cc
+++ b/src/cobalt/dom/rule_matching_test.cc
@@ -30,6 +30,7 @@
#include "cobalt/dom/node.h"
#include "cobalt/dom/node_descendants_iterator.h"
#include "cobalt/dom/node_list.h"
+#include "cobalt/dom/testing/stub_window.h"
#include "cobalt/dom_parser/parser.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -229,9 +230,15 @@
// div:focus should match focused div.
TEST_F(RuleMatchingTest, FocusPseudoClassMatch) {
+ // Give the document browsing context which is needed for focus to work.
+ testing::StubWindow window;
+ document_->set_window(window.window());
+ // Give the document initial computed style.
+ document_->SetViewport(math::Size(320, 240));
+
css_style_sheet_ = css_parser_->ParseStyleSheet(
":focus {}", base::SourceLocation("[object RuleMatchingTest]", 1, 1));
- root_->set_inner_html("<div tabIndex=-1/>");
+ root_->set_inner_html("<div tabIndex=\"-1\"/>");
root_->first_element_child()->AsHTMLElement()->Focus();
UpdateAllMatchingRules();
@@ -243,9 +250,15 @@
// div:focus shouldn't match unfocused div.
TEST_F(RuleMatchingTest, FocusPseudoClassNoMatch) {
+ // Give the document browsing context which is needed for focus to work.
+ testing::StubWindow window;
+ document_->set_window(window.window());
+ // Give the document initial computed style.
+ document_->SetViewport(math::Size(320, 240));
+
css_style_sheet_ = css_parser_->ParseStyleSheet(
":focus {}", base::SourceLocation("[object RuleMatchingTest]", 1, 1));
- root_->set_inner_html("<div tabIndex=-1/>");
+ root_->set_inner_html("<div tabIndex=\"-1\"/>");
UpdateAllMatchingRules();
cssom::RulesWithCascadePrecedence* matching_rules =
diff --git a/src/cobalt/webdriver/testing/stub_window.h b/src/cobalt/dom/testing/stub_window.h
similarity index 88%
rename from src/cobalt/webdriver/testing/stub_window.h
rename to src/cobalt/dom/testing/stub_window.h
index e2751dc..ffe7834 100644
--- a/src/cobalt/webdriver/testing/stub_window.h
+++ b/src/cobalt/dom/testing/stub_window.h
@@ -12,8 +12,8 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-#ifndef COBALT_WEBDRIVER_TESTING_STUB_WINDOW_H_
-#define COBALT_WEBDRIVER_TESTING_STUB_WINDOW_H_
+#ifndef COBALT_DOM_TESTING_STUB_WINDOW_H_
+#define COBALT_DOM_TESTING_STUB_WINDOW_H_
#include <string>
@@ -28,14 +28,16 @@
#include "cobalt/media/media_module_stub.h"
#include "cobalt/media_session/media_session.h"
#include "cobalt/network/network_module.h"
+#include "cobalt/script/global_environment.h"
+#include "cobalt/script/javascript_engine.h"
#include "googleurl/src/gurl.h"
namespace cobalt {
-namespace webdriver {
+namespace dom {
namespace testing {
-// A helper class for WebDriver tests that brings up a dom::Window with a number
-// of parts stubbed out.
+// A helper class for tests that brings up a dom::Window with a number of parts
+// stubbed out.
class StubWindow {
public:
StubWindow()
@@ -70,6 +72,7 @@
scoped_refptr<script::GlobalEnvironment> global_environment() {
return global_environment_;
}
+ css_parser::Parser* css_parser() { return css_parser_.get(); }
private:
static void StubErrorCallback(const std::string& /*error*/) {}
@@ -90,7 +93,7 @@
};
} // namespace testing
-} // namespace webdriver
+} // namespace dom
} // namespace cobalt
-#endif // COBALT_WEBDRIVER_TESTING_STUB_WINDOW_H_
+#endif // COBALT_DOM_TESTING_STUB_WINDOW_H_
diff --git a/src/cobalt/dom/ui_event.cc b/src/cobalt/dom/ui_event.cc
index a9ebec2..2b4d274 100644
--- a/src/cobalt/dom/ui_event.cc
+++ b/src/cobalt/dom/ui_event.cc
@@ -25,8 +25,6 @@
UIEvent::UIEvent(UninitializedFlag uninitialized_flag)
: Event(uninitialized_flag) {}
-UIEvent::UIEvent(base::Token type) : Event(type) {}
-
UIEvent::UIEvent(base::Token type, Bubbles bubbles, Cancelable cancelable)
: Event(type, bubbles, cancelable) {}
@@ -38,5 +36,7 @@
view_ = view;
}
+UIEvent::UIEvent(base::Token type) : Event(type) {}
+
} // namespace dom
} // namespace cobalt
diff --git a/src/cobalt/dom/ui_event.h b/src/cobalt/dom/ui_event.h
index a1e669f..6659231 100644
--- a/src/cobalt/dom/ui_event.h
+++ b/src/cobalt/dom/ui_event.h
@@ -36,6 +36,8 @@
// Creates an event with its "initialized flag" unset.
explicit UIEvent(UninitializedFlag uninitialized_flag);
+ UIEvent(base::Token type, Bubbles bubbles, Cancelable cancelable);
+
// Web API: UIEvent
//
void InitUIEvent(const std::string& type, bool bubbles, bool cancelable,
@@ -52,7 +54,6 @@
protected:
explicit UIEvent(base::Token type);
- UIEvent(base::Token type, Bubbles bubbles, Cancelable cancelable);
~UIEvent() OVERRIDE {}
diff --git a/src/cobalt/media/base/drm_system.h b/src/cobalt/media/base/drm_system.h
index 8596241..7a400c8 100644
--- a/src/cobalt/media/base/drm_system.h
+++ b/src/cobalt/media/base/drm_system.h
@@ -18,6 +18,7 @@
#include <string>
#include "base/hash_tables.h"
+#include "base/memory/ref_counted.h"
#include "base/memory/scoped_ptr.h"
#include "base/memory/weak_ptr.h"
#include "base/message_loop.h"
@@ -35,7 +36,7 @@
//
// Ensures that callbacks are always asynchronous and performed
// from the same thread where |DrmSystem| was instantiated.
-class DrmSystem {
+class DrmSystem : public base::RefCounted<DrmSystem> {
public:
typedef base::Callback<void(scoped_array<uint8> message, int message_size)>
SessionUpdateRequestGeneratedCallback;
@@ -44,7 +45,8 @@
typedef base::Callback<void()> SessionDidNotUpdateCallback;
// Flyweight that provides RAII semantics for sessions.
- // Most of logic is implemented by |DrmSystem|.
+ // Most of logic is implemented by |DrmSystem| and thus sessions must be
+ // destroyed before |DrmSystem|.
class Session {
public:
~Session();
diff --git a/src/cobalt/media/base/sbplayer_pipeline.cc b/src/cobalt/media/base/sbplayer_pipeline.cc
index 40763c6..b773589 100644
--- a/src/cobalt/media/base/sbplayer_pipeline.cc
+++ b/src/cobalt/media/base/sbplayer_pipeline.cc
@@ -330,6 +330,7 @@
if (!player_) {
seek_cb.Run(PIPELINE_ERROR_INVALID_STATE);
+ return;
}
player_->PrepareForSeek();
diff --git a/src/cobalt/media/base/starboard_player.cc b/src/cobalt/media/base/starboard_player.cc
index 01d4a3c..e4ce5be 100644
--- a/src/cobalt/media/base/starboard_player.cc
+++ b/src/cobalt/media/base/starboard_player.cc
@@ -124,7 +124,9 @@
->ResetGetCurrentSbDecodeTargetFunction();
#endif // SB_API_VERSION >= 4
- SbPlayerDestroy(player_);
+ if (SbPlayerIsValid(player_)) {
+ SbPlayerDestroy(player_);
+ }
}
void StarboardPlayer::UpdateVideoResolution(int frame_width, int frame_height) {
@@ -203,8 +205,13 @@
}
void StarboardPlayer::SetBounds(const gfx::Rect& rect) {
- DCHECK(SbPlayerIsValid(player_));
+ if (state_ == kSuspended) {
+ DCHECK(!SbPlayerIsValid(player_));
+ pending_set_bounds_rect_ = rect;
+ return;
+ }
+ DCHECK(SbPlayerIsValid(player_));
#if SB_API_VERSION >= 4
const int kZIndex = 0;
SbPlayerSetBounds(player_, kZIndex, rect.x(), rect.y(), rect.width(),
@@ -216,13 +223,20 @@
void StarboardPlayer::PrepareForSeek() {
DCHECK(message_loop_->BelongsToCurrentThread());
+
+ seek_pending_ = true;
+
+ if (state_ == kSuspended) {
+ DCHECK(!SbPlayerIsValid(player_));
+ return;
+ }
+
++ticket_;
#if SB_API_VERSION < 4
SbPlayerSetPause(player_, true);
#else // SB_API_VERSION < 4
SbPlayerSetPlaybackRate(player_, 0.f);
#endif // SB_API_VERSION < 4
- seek_pending_ = true;
}
void StarboardPlayer::Seek(base::TimeDelta time) {
@@ -270,9 +284,14 @@
void StarboardPlayer::SetPlaybackRate(double playback_rate) {
DCHECK(message_loop_->BelongsToCurrentThread());
- DCHECK(SbPlayerIsValid(player_));
playback_rate_ = playback_rate;
+
+ if (state_ == kSuspended) {
+ DCHECK(!SbPlayerIsValid(player_));
+ return;
+ }
+
#if SB_API_VERSION < 4
SbPlayerSetPause(player_, playback_rate == 0.0);
#else // SB_API_VERSION < 4
@@ -451,6 +470,11 @@
#endif // SB_API_VERSION >= 4
set_bounds_helper_->SetPlayer(this);
+
+ if (pending_set_bounds_rect_) {
+ SetBounds(*pending_set_bounds_rect_);
+ pending_set_bounds_rect_ = base::nullopt_t();
+ }
}
#if SB_API_VERSION >= 4
diff --git a/src/cobalt/media/base/starboard_player.h b/src/cobalt/media/base/starboard_player.h
index 5acfecd..d2c02f1 100644
--- a/src/cobalt/media/base/starboard_player.h
+++ b/src/cobalt/media/base/starboard_player.h
@@ -157,6 +157,10 @@
bool paused_;
bool seek_pending_;
DecoderBufferCache decoder_buffer_cache_;
+ // If |SetBounds| is called while we are in a suspended state, then the
+ // |Rect| that we are passed will be saved to here, and then immediately set
+ // on the new player that we construct when we are resumed.
+ base::optional<gfx::Rect> pending_set_bounds_rect_;
// The following variables can be accessed from GetInfo(), which can be called
// from any threads. So some of their usages have to be guarded by |lock_|.
diff --git a/src/cobalt/media/decoder_buffer_allocator.cc b/src/cobalt/media/decoder_buffer_allocator.cc
index f60a1c7..70858e5 100644
--- a/src/cobalt/media/decoder_buffer_allocator.cc
+++ b/src/cobalt/media/decoder_buffer_allocator.cc
@@ -22,32 +22,52 @@
namespace media {
namespace {
-bool kPreAllocateAllMemory = true;
+const bool kPreAllocateAllMemory = true;
} // namespace
-DecoderBufferAllocator::DecoderBufferAllocator()
- : memory_block_(
- SbMemoryAllocateAligned(DecoderBuffer::kAlignmentSize,
- COBALT_MEDIA_BUFFER_INITIAL_CAPACITY)) {
- memory_pool_.set(starboard::make_scoped_ptr(
- new nb::MemoryPool(memory_block_, COBALT_MEDIA_BUFFER_INITIAL_CAPACITY,
- kPreAllocateAllMemory)));
+DecoderBufferAllocator::DecoderBufferAllocator() : memory_block_(NULL) {
+ if (COBALT_MEDIA_BUFFER_INITIAL_CAPACITY > 0) {
+ memory_block_ = SbMemoryAllocateAligned(
+ DecoderBuffer::kAlignmentSize, COBALT_MEDIA_BUFFER_INITIAL_CAPACITY);
+ }
+
+ if (COBALT_MEDIA_BUFFER_INITIAL_CAPACITY > 0 ||
+ COBALT_MEDIA_BUFFER_ALLOCATION_UNIT > 0) {
+ // TODO: Support COBALT_MEDIA_BUFFER_ALLOCATION_UNIT > 0.
+ memory_pool_.set(starboard::make_scoped_ptr(
+ new nb::MemoryPool(memory_block_, COBALT_MEDIA_BUFFER_INITIAL_CAPACITY,
+ kPreAllocateAllMemory)));
+ }
}
DecoderBufferAllocator::~DecoderBufferAllocator() {
- DCHECK_EQ(memory_pool_->GetAllocated(), 0);
- SbMemoryDeallocateAligned(memory_block_);
+ if (memory_pool_.is_valid()) {
+ DCHECK_EQ(memory_pool_->GetAllocated(), 0);
+ }
+
+ if (memory_block_) {
+ SbMemoryDeallocateAligned(memory_block_);
+ }
}
void* DecoderBufferAllocator::Allocate(Type type, size_t size,
size_t alignment) {
UNREFERENCED_PARAMETER(type);
- return memory_pool_->Allocate(size, alignment);
+ if (memory_pool_.is_valid()) {
+ return memory_pool_->Allocate(size, alignment);
+ }
+
+ return SbMemoryAllocateAligned(alignment, size);
}
void DecoderBufferAllocator::Free(Type type, void* ptr) {
UNREFERENCED_PARAMETER(type);
- memory_pool_->Free(ptr);
+ if (memory_pool_.is_valid()) {
+ memory_pool_->Free(ptr);
+ return;
+ }
+
+ SbMemoryDeallocateAligned(ptr);
}
} // namespace media
diff --git a/src/cobalt/media/player/web_media_player_impl.cc b/src/cobalt/media/player/web_media_player_impl.cc
index c8477bd..9741314 100644
--- a/src/cobalt/media/player/web_media_player_impl.cc
+++ b/src/cobalt/media/player/web_media_player_impl.cc
@@ -32,6 +32,9 @@
namespace {
+// Used to ensure that there is no more than one instance of WebMediaPlayerImpl.
+WebMediaPlayerImpl* s_instance;
+
// Limits the range of playback rate.
//
// TODO(kylep): Revisit these.
@@ -124,6 +127,9 @@
drm_system_(NULL) {
TRACE_EVENT0("cobalt::media", "WebMediaPlayerImpl::WebMediaPlayerImpl");
+ DCHECK(!s_instance);
+ s_instance = this;
+
DCHECK(buffer_allocator_);
media_log_->AddEvent(
media_log_->CreateEvent(MediaLogEvent::WEBMEDIAPLAYER_CREATED));
@@ -145,6 +151,9 @@
DCHECK(!main_loop_ || main_loop_ == MessageLoop::current());
+ DCHECK_EQ(s_instance, this);
+ s_instance = NULL;
+
if (delegate_) {
delegate_->UnregisterPlayer(this);
}
diff --git a/src/cobalt/script/mozjs-45/mozjs-45.gyp b/src/cobalt/script/mozjs-45/mozjs-45.gyp
index 6959bcd..2a38204 100644
--- a/src/cobalt/script/mozjs-45/mozjs-45.gyp
+++ b/src/cobalt/script/mozjs-45/mozjs-45.gyp
@@ -27,7 +27,6 @@
'mozjs_property_enumerator.cc',
'mozjs_script_value_factory.cc',
'mozjs_source_code.cc',
- 'opaque_root_tracker.cc',
'promise_wrapper.cc',
'proxy_handler.cc',
'referenced_object_map.cc',
diff --git a/src/cobalt/script/mozjs-45/mozjs_global_environment.cc b/src/cobalt/script/mozjs-45/mozjs_global_environment.cc
index 2bd7c41..32cf999 100644
--- a/src/cobalt/script/mozjs-45/mozjs_global_environment.cc
+++ b/src/cobalt/script/mozjs-45/mozjs_global_environment.cc
@@ -140,8 +140,6 @@
wrapper_factory_.reset(new WrapperFactory(context_));
script_value_factory_.reset(new MozjsScriptValueFactory(this));
referenced_objects_.reset(new ReferencedObjectMap(context_));
- opaque_root_tracker_.reset(new OpaqueRootTracker(
- context_, referenced_objects_.get(), wrapper_factory_.get()));
JS_AddExtraGCRootsTracer(runtime, TraceFunction, this);
}
@@ -400,37 +398,20 @@
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. Also, only verify that |visisted_wrappables_| is
- // empty in this case.
- // TODO: Opaque root logic is a special case of tracing wrappables, and
- // should be removed.
+ // BeginGarbageCollection callback. Only verify that |visisted_wrappables_|
+ // is empty the first time we enter.
garbage_collection_count_++;
if (garbage_collection_count_ == 1) {
- if (global_object_proxy_) {
- DCHECK(!opaque_root_state_);
- JSAutoRequest auto_request(context_);
- JSAutoCompartment auto_compartment(context_, global_object_proxy_);
- // Get the current state of opaque root relationships. Keep this object
- // alive for the duration of the GC phase to ensure that reachability
- // between roots and reachable objects is maintained.
- opaque_root_state_ = opaque_root_tracker_->GetCurrentOpaqueRootState();
- }
-
DCHECK_EQ(visited_wrappables_.size(), 0);
}
}
void MozjsGlobalEnvironment::EndGarbageCollection() {
- // Reset opaque root reachability relationships. Also reset
- // |visisted_wrappables_|.
- // TODO: Opaque root logic is a special case of tracing wrappables, and
- // should be removed.
+ // Reset |visisted_wrappables_|.
garbage_collection_count_--;
DCHECK_GE(garbage_collection_count_, 0);
if (garbage_collection_count_ == 0) {
- opaque_root_state_.reset(NULL);
visited_wrappables_.clear();
}
}
diff --git a/src/cobalt/script/mozjs-45/mozjs_global_environment.h b/src/cobalt/script/mozjs-45/mozjs_global_environment.h
index 0a5a573..bcb0a54 100644
--- a/src/cobalt/script/mozjs-45/mozjs_global_environment.h
+++ b/src/cobalt/script/mozjs-45/mozjs_global_environment.h
@@ -25,7 +25,6 @@
#include "cobalt/script/global_environment.h"
#include "cobalt/script/javascript_engine.h"
#include "cobalt/script/mozjs-45/interface_data.h"
-#include "cobalt/script/mozjs-45/opaque_root_tracker.h"
#include "cobalt/script/mozjs-45/util/exception_helpers.h"
#include "cobalt/script/mozjs-45/weak_heap_object_manager.h"
#include "cobalt/script/mozjs-45/wrapper_factory.h"
@@ -99,10 +98,6 @@
WeakHeapObjectManager* weak_object_manager() { return &weak_object_manager_; }
- OpaqueRootTracker* opaque_root_tracker() {
- return opaque_root_tracker_.get();
- }
-
base::hash_set<Wrappable*>* visited_wrappables() {
return &visited_wrappables_;
}
@@ -172,13 +167,11 @@
WeakHeapObjectManager weak_object_manager_;
CachedWrapperMultiMap kept_alive_objects_;
scoped_ptr<ReferencedObjectMap> referenced_objects_;
- scoped_ptr<OpaqueRootTracker> opaque_root_tracker_;
CachedInterfaceData cached_interface_data_;
STLValueDeleter<CachedInterfaceData> cached_interface_data_deleter_;
ContextDestructor context_destructor_;
scoped_ptr<WrapperFactory> wrapper_factory_;
scoped_ptr<MozjsScriptValueFactory> script_value_factory_;
- scoped_ptr<OpaqueRootTracker::OpaqueRootState> opaque_root_state_;
JS::Heap<JSObject*> global_object_proxy_;
EnvironmentSettings* environment_settings_;
// TODO: Should be |std::unordered_set| once C++11 is enabled.
diff --git a/src/cobalt/script/mozjs-45/opaque_root_tracker.cc b/src/cobalt/script/mozjs-45/opaque_root_tracker.cc
deleted file mode 100644
index fdce7cf..0000000
--- a/src/cobalt/script/mozjs-45/opaque_root_tracker.cc
+++ /dev/null
@@ -1,143 +0,0 @@
-// 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/script/mozjs-45/opaque_root_tracker.h"
-
-#include <utility>
-#include <vector>
-
-#include "cobalt/script/mozjs-45/weak_heap_object.h"
-#include "third_party/mozjs-45/js/src/jsapi.h"
-
-namespace cobalt {
-namespace script {
-namespace mozjs {
-namespace {
-// Implementation of OpaqueRootTracker::OpaqueRootState.
-// On creation, this class will register reachability between objects and their
-// roots in |ReferencedObjectMap|. On destruction, the reachability
-// relationship will be removed.
-class OpaqueRootStateImpl : public OpaqueRootTracker::OpaqueRootState {
- public:
- OpaqueRootStateImpl(JSContext* context,
- ReferencedObjectMap* referenced_object_map)
- : context_(context), referenced_object_map_(referenced_object_map) {}
-
- void TrackReachability(WrapperPrivate* from, WrapperPrivate* to) {
- intptr_t from_key = ReferencedObjectMap::GetKeyForWrappable(
- from->wrappable<Wrappable>().get());
- JSObject* to_proxy = to->js_object_proxy();
- DCHECK(to_proxy);
- JS::RootedValue to_value(context_, JS::ObjectValue(*to_proxy));
- referenced_objects_.push_back(
- std::make_pair(from_key, WeakHeapObject(context_, to_value)));
- referenced_object_map_->AddReferencedObject(from_key, to_value);
- }
-
- ~OpaqueRootStateImpl() {
- JSAutoRequest auto_request(context_);
- for (ReferencedObjectPairVector::iterator it = referenced_objects_.begin();
- it != referenced_objects_.end(); ++it) {
- WeakHeapObject &value = it->second;
- if (value.IsGcThing() && !value.WasCollected()) {
- JS::RootedValue reachable_value(context_, it->second.GetValue());
- referenced_object_map_->RemoveReferencedObject(it->first,
- reachable_value);
- }
- }
- }
-
- private:
- typedef std::vector<std::pair<intptr_t, WeakHeapObject> >
- ReferencedObjectPairVector;
-
- JSContext* context_;
- ReferencedObjectMap* referenced_object_map_;
- ReferencedObjectPairVector referenced_objects_;
-};
-} // namespace
-
-OpaqueRootTracker::OpaqueRootTracker(JSContext* context,
- ReferencedObjectMap* referenced_object_map,
- WrapperFactory* wrapper_factory)
- : context_(context),
- referenced_object_map_(referenced_object_map),
- wrapper_factory_(wrapper_factory) {}
-
-void OpaqueRootTracker::AddObjectWithOpaqueRoot(
- WrapperPrivate* wrapper_private) {
- all_objects_.insert(wrapper_private);
-}
-
-void OpaqueRootTracker::RemoveObjectWithOpaqueRoot(
- WrapperPrivate* wrapper_private) {
- all_objects_.erase(wrapper_private);
-}
-
-scoped_ptr<OpaqueRootTracker::OpaqueRootState>
-OpaqueRootTracker::GetCurrentOpaqueRootState() {
- scoped_ptr<OpaqueRootStateImpl> state(
- new OpaqueRootStateImpl(context_, referenced_object_map_));
- // Get the current opaque root for all objects that are being tracked.
- for (WrapperPrivateSet::iterator it = all_objects_.begin();
- it != all_objects_.end(); ++it) {
- WrapperPrivate* wrapper_private = *it;
- TrackReachabilityToOpaqueRoot(state.get(), wrapper_private);
- TrackReachableWrappables(state.get(), wrapper_private);
- }
- return state.PassAs<OpaqueRootState>();
-}
-
-void OpaqueRootTracker::TrackReachabilityToOpaqueRoot(
- OpaqueRootState* state, WrapperPrivate* wrapper_private) {
- OpaqueRootStateImpl* state_impl =
- base::polymorphic_downcast<OpaqueRootStateImpl*>(state);
- // If this wrappable has an opaque root, track reachability between this
- // wrappable and its root.
- Wrappable* opaque_root = wrapper_private->GetOpaqueRoot();
- if (opaque_root) {
- WrapperPrivate* opaque_root_private = WrapperPrivate::GetFromWrappable(
- opaque_root, context_, wrapper_factory_);
- // Always mark the root as reachable from the non-root object.
- state_impl->TrackReachability(wrapper_private, opaque_root_private);
-
- // Only mark the non-root object as reachable if we need to keep the
- // wrapper alive for some reason. In general it's okay for a wrapper to
- // get GC'd because the Cobalt object will still be kept alive, and a new
- // JS object can be created if needed again.
- if (wrapper_private->ShouldKeepWrapperAliveIfReachable()) {
- state_impl->TrackReachability(opaque_root_private, wrapper_private);
- }
- }
-}
-
-void OpaqueRootTracker::TrackReachableWrappables(
- OpaqueRootState* state, WrapperPrivate* wrapper_private) {
- OpaqueRootStateImpl* state_impl =
- base::polymorphic_downcast<OpaqueRootStateImpl*>(state);
- // Track any wrappables that are explicitly marked as reachable from
- // this wrappable.
- typedef std::vector<Wrappable*> WrappableVector;
- WrappableVector reachable_objects;
- wrapper_private->GetReachableWrappables(&reachable_objects);
- for (size_t i = 0; i < reachable_objects.size(); ++i) {
- WrapperPrivate* reachable_object_private = WrapperPrivate::GetFromWrappable(
- reachable_objects[i], context_, wrapper_factory_);
- state_impl->TrackReachability(wrapper_private, reachable_object_private);
- }
-}
-
-} // namespace mozjs
-} // namespace script
-} // namespace cobalt
diff --git a/src/cobalt/script/mozjs-45/opaque_root_tracker.h b/src/cobalt/script/mozjs-45/opaque_root_tracker.h
deleted file mode 100644
index f09ed04..0000000
--- a/src/cobalt/script/mozjs-45/opaque_root_tracker.h
+++ /dev/null
@@ -1,89 +0,0 @@
-// 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_SCRIPT_MOZJS_45_OPAQUE_ROOT_TRACKER_H_
-#define COBALT_SCRIPT_MOZJS_45_OPAQUE_ROOT_TRACKER_H_
-
-#include "base/hash_tables.h"
-#include "cobalt/script/mozjs-45/referenced_object_map.h"
-#include "cobalt/script/mozjs-45/wrapper_factory.h"
-#include "cobalt/script/mozjs-45/wrapper_private.h"
-
-namespace cobalt {
-namespace script {
-namespace mozjs {
-
-// This class manages lifetime of structures containing objects that are
-// reachable from through the interface implementation, but not through
-// JavaScript, by ensuring that the root of the structure is not garbage
-// collected if any of the members of the structure are reachable.
-//
-// The implementation of the structure in Cobalt is typically reference counted.
-// The |root| of that structure is a single node that transitively holds a
-// reference to every other node in the structure. It may be the case that the
-// only reference to that root node is from a JS object's WrapperPrivate. The
-// OpaqueRootTracker class ensures that if some node in the structure is
-// reachable from JavaScript, the JS object holding the reference to the root
-// of the structure is marked as reachable as well, which preserves the final
-// reference to the root of the structure, keeping the entire structure alive.
-//
-// For example, any DOM Node can be reached from any other DOM Node object in
-// the same tree. If an arbitary internal Node is reachable from JavaScript,
-// this class will ensure that the root of the tree will also be kept alive,
-// preserving the entire tree until no nodes in the tree are reachable from
-// JavaScript.
-//
-// An object's opaque root can change throughout the object's lifetime, so the
-// root needs to be recalculated every garbage collection phase.
-class OpaqueRootTracker {
- public:
- // Callers do not need to operate on this class. They just need to manage its
- // lifetime appropriately as described below.
- class OpaqueRootState {
- protected:
- OpaqueRootState() {}
- virtual ~OpaqueRootState() {}
- friend class scoped_ptr<OpaqueRootState>;
- };
-
- OpaqueRootTracker(JSContext* context,
- ReferencedObjectMap* referenced_object_map,
- WrapperFactory* wrapper_factory);
-
- // All objects that implement this functionality must be registered to this
- // class.
- void AddObjectWithOpaqueRoot(WrapperPrivate* wrapper_private);
- void RemoveObjectWithOpaqueRoot(WrapperPrivate* wrapper_private);
-
- // Get the current state of opaque roots. This should be called when garbage
- // collection begins before marking has begun. Once garbage collection is
- // complete, this should be released.
- scoped_ptr<OpaqueRootState> GetCurrentOpaqueRootState();
-
- private:
- void TrackReachabilityToOpaqueRoot(OpaqueRootState* state,
- WrapperPrivate* wrapper_private);
- void TrackReachableWrappables(OpaqueRootState* state,
- WrapperPrivate* wrapper_private);
- typedef base::hash_set<WrapperPrivate*> WrapperPrivateSet;
-
- JSContext* context_;
- ReferencedObjectMap* referenced_object_map_;
- WrapperFactory* wrapper_factory_;
- // list of objects that are potentially reachable from an opaque root
- WrapperPrivateSet all_objects_;
-};
-} // namespace mozjs
-} // namespace script
-} // namespace cobalt
-#endif // COBALT_SCRIPT_MOZJS_45_OPAQUE_ROOT_TRACKER_H_
diff --git a/src/cobalt/script/mozjs-45/wrapper_private.cc b/src/cobalt/script/mozjs-45/wrapper_private.cc
index 44a0930..e344ef3 100644
--- a/src/cobalt/script/mozjs-45/wrapper_private.cc
+++ b/src/cobalt/script/mozjs-45/wrapper_private.cc
@@ -89,40 +89,13 @@
}
}
-Wrappable* WrapperPrivate::GetOpaqueRoot() const {
- if (!get_opaque_root_function_.is_null()) {
- return get_opaque_root_function_.Run(wrappable_);
- }
- return NULL;
-}
-
-void WrapperPrivate::GetReachableWrappables(
- std::vector<Wrappable*>* reachable) {
- if (!get_reachable_wrappables_function_.is_null()) {
- return get_reachable_wrappables_function_.Run(wrappable_, reachable);
- }
-}
-
-bool WrapperPrivate::ShouldKeepWrapperAliveIfReachable() {
- const ProxyHandler* proxy_handler =
- base::polymorphic_downcast<const ProxyHandler*>(
- js::GetProxyHandler(wrapper_proxy_));
-
- DCHECK(proxy_handler);
- return proxy_handler->has_custom_property() ||
- wrappable_->ShouldKeepWrapperAlive();
-}
-
// static
-void WrapperPrivate::AddPrivateData(
- JSContext* context, JS::HandleObject wrapper_proxy,
- const scoped_refptr<Wrappable>& wrappable,
- const GetOpaqueRootFunction& get_opaque_root_function,
- const GetReachableWrappablesFunction& get_reachable_wrappables_function) {
+void WrapperPrivate::AddPrivateData(JSContext* context,
+ JS::HandleObject wrapper_proxy,
+ const scoped_refptr<Wrappable>& wrappable) {
DCHECK(js::IsProxy(wrapper_proxy));
- WrapperPrivate* private_data = new WrapperPrivate(
- context, wrappable, wrapper_proxy, get_opaque_root_function,
- get_reachable_wrappables_function);
+ WrapperPrivate* private_data =
+ new WrapperPrivate(context, wrappable, wrapper_proxy);
JS::RootedObject target_object(context,
js::GetProxyTargetObject(wrapper_proxy));
JS_SetPrivate(target_object, private_data);
@@ -220,32 +193,14 @@
}
}
-WrapperPrivate::WrapperPrivate(
- JSContext* context, const scoped_refptr<Wrappable>& wrappable,
- JS::HandleObject wrapper_proxy,
- const GetOpaqueRootFunction& get_opaque_root_function,
- const GetReachableWrappablesFunction& get_reachable_wrappables_function)
- : context_(context),
- wrappable_(wrappable),
- wrapper_proxy_(wrapper_proxy),
- get_opaque_root_function_(get_opaque_root_function),
- get_reachable_wrappables_function_(get_reachable_wrappables_function) {
+WrapperPrivate::WrapperPrivate(JSContext* context,
+ const scoped_refptr<Wrappable>& wrappable,
+ JS::HandleObject wrapper_proxy)
+ : context_(context), wrappable_(wrappable), wrapper_proxy_(wrapper_proxy) {
DCHECK(js::IsProxy(wrapper_proxy));
- if (!get_opaque_root_function_.is_null() ||
- !get_reachable_wrappables_function_.is_null()) {
- MozjsGlobalEnvironment* global_environment =
- MozjsGlobalEnvironment::GetFromContext(context_);
- global_environment->opaque_root_tracker()->AddObjectWithOpaqueRoot(this);
- }
}
WrapperPrivate::~WrapperPrivate() {
- if (!get_opaque_root_function_.is_null() ||
- !get_reachable_wrappables_function_.is_null()) {
- MozjsGlobalEnvironment* global_environment =
- MozjsGlobalEnvironment::GetFromContext(context_);
- global_environment->opaque_root_tracker()->RemoveObjectWithOpaqueRoot(this);
- }
wrapper_proxy_ = NULL;
}
diff --git a/src/cobalt/script/mozjs-45/wrapper_private.h b/src/cobalt/script/mozjs-45/wrapper_private.h
index 7e4b917..0483cea 100644
--- a/src/cobalt/script/mozjs-45/wrapper_private.h
+++ b/src/cobalt/script/mozjs-45/wrapper_private.h
@@ -58,10 +58,6 @@
class WrapperPrivate : public base::SupportsWeakPtr<WrapperPrivate> {
public:
typedef std::vector<Wrappable*> WrappableVector;
- typedef base::Callback<Wrappable*(const scoped_refptr<Wrappable>&)>
- GetOpaqueRootFunction;
- typedef base::Callback<void(const scoped_refptr<Wrappable>&,
- WrappableVector*)> GetReachableWrappablesFunction;
template <typename T>
scoped_refptr<T> wrappable() const {
@@ -70,25 +66,9 @@
JSObject* js_object_proxy() const { return wrapper_proxy_; }
- Wrappable* GetOpaqueRoot() const;
- void GetReachableWrappables(std::vector<Wrappable*>* reachable);
-
- // Return true if the GC should avoid collecting this wrapper. Note that if
- // the wrapper is unreachable, it may still be collected.
- bool ShouldKeepWrapperAliveIfReachable();
-
// Create a new WrapperPrivate instance and associate it with the wrapper.
- static void AddPrivateData(
- JSContext* context, JS::HandleObject wrapper_proxy,
- const scoped_refptr<Wrappable>& wrappable,
- const GetOpaqueRootFunction& get_opaque_root_function,
- const GetReachableWrappablesFunction& get_reachable_wrappables_function);
-
static void AddPrivateData(JSContext* context, JS::HandleObject wrapper_proxy,
- const scoped_refptr<Wrappable>& wrappable) {
- AddPrivateData(context, wrapper_proxy, wrappable, GetOpaqueRootFunction(),
- GetReachableWrappablesFunction());
- }
+ const scoped_refptr<Wrappable>& wrappable);
// Return true if the object has wrapper private.
static bool HasWrapperPrivate(JSContext* context, JS::HandleObject object);
@@ -118,18 +98,13 @@
static void Trace(JSTracer* trace, JSObject* object);
private:
- WrapperPrivate(
- JSContext* context, const scoped_refptr<Wrappable>& wrappable,
- JS::HandleObject wrapper_proxy,
- const GetOpaqueRootFunction& get_opaque_root_function,
- const GetReachableWrappablesFunction& get_reachable_wrappables_function);
+ WrapperPrivate(JSContext* context, const scoped_refptr<Wrappable>& wrappable,
+ JS::HandleObject wrapper_proxy);
~WrapperPrivate();
JSContext* context_;
scoped_refptr<Wrappable> wrappable_;
JS::Heap<JSObject*> wrapper_proxy_;
- GetOpaqueRootFunction get_opaque_root_function_;
- GetReachableWrappablesFunction get_reachable_wrappables_function_;
friend Tracer;
};
diff --git a/src/cobalt/script/mozjs/mozjs.gyp b/src/cobalt/script/mozjs/mozjs.gyp
index ce2763c..1a2a752 100644
--- a/src/cobalt/script/mozjs/mozjs.gyp
+++ b/src/cobalt/script/mozjs/mozjs.gyp
@@ -28,7 +28,6 @@
'mozjs_script_value_factory.cc',
'mozjs_source_code.cc',
'mozjs_trace_logging.cc',
- 'opaque_root_tracker.cc',
'promise_wrapper.cc',
'proxy_handler.cc',
'referenced_object_map.cc',
diff --git a/src/cobalt/script/mozjs/mozjs_global_environment.cc b/src/cobalt/script/mozjs/mozjs_global_environment.cc
index e306a50..e7d64a1 100644
--- a/src/cobalt/script/mozjs/mozjs_global_environment.cc
+++ b/src/cobalt/script/mozjs/mozjs_global_environment.cc
@@ -162,8 +162,6 @@
wrapper_factory_.reset(new WrapperFactory(context_));
script_value_factory_.reset(new MozjsScriptValueFactory(this));
referenced_objects_.reset(new ReferencedObjectMap(context_));
- opaque_root_tracker_.reset(new OpaqueRootTracker(
- context_, referenced_objects_.get(), wrapper_factory_.get()));
JS_AddExtraGCRootsTracer(runtime, TraceFunction, this);
}
@@ -394,37 +392,20 @@
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. Also, only verify that |visisted_wrappables_| is
- // empty in this case.
- // TODO: Opaque root logic is a special case of tracing wrappables, and
- // should be removed.
+ // BeginGarbageCollection callback. Only verify that |visisted_wrappables_|
+ // is empty the first time we enter.
garbage_collection_count_++;
if (garbage_collection_count_ == 1) {
- if (global_object_proxy_) {
- DCHECK(!opaque_root_state_);
- JSAutoRequest auto_request(context_);
- JSAutoCompartment auto_compartment(context_, global_object_proxy_);
- // Get the current state of opaque root relationships. Keep this object
- // alive for the duration of the GC phase to ensure that reachability
- // between roots and reachable objects is maintained.
- opaque_root_state_ = opaque_root_tracker_->GetCurrentOpaqueRootState();
- }
-
DCHECK_EQ(visited_wrappables_.size(), 0);
}
}
void MozjsGlobalEnvironment::EndGarbageCollection() {
- // Reset opaque root reachability relationships. Also reset
- // |visisted_wrappables_|.
- // TODO: Opaque root logic is a special case of tracing wrappables, and
- // should be removed.
+ // Reset |visisted_wrappables_|.
garbage_collection_count_--;
DCHECK_GE(garbage_collection_count_, 0);
if (garbage_collection_count_ == 0) {
- opaque_root_state_.reset(NULL);
visited_wrappables_.clear();
}
}
diff --git a/src/cobalt/script/mozjs/mozjs_global_environment.h b/src/cobalt/script/mozjs/mozjs_global_environment.h
index 6c79872..4914e18 100644
--- a/src/cobalt/script/mozjs/mozjs_global_environment.h
+++ b/src/cobalt/script/mozjs/mozjs_global_environment.h
@@ -25,7 +25,6 @@
#include "cobalt/script/global_environment.h"
#include "cobalt/script/javascript_engine.h"
#include "cobalt/script/mozjs/interface_data.h"
-#include "cobalt/script/mozjs/opaque_root_tracker.h"
#include "cobalt/script/mozjs/util/exception_helpers.h"
#include "cobalt/script/mozjs/weak_heap_object_manager.h"
#include "cobalt/script/mozjs/wrapper_factory.h"
@@ -98,10 +97,6 @@
WeakHeapObjectManager* weak_object_manager() { return &weak_object_manager_; }
- OpaqueRootTracker* opaque_root_tracker() {
- return opaque_root_tracker_.get();
- }
-
base::hash_set<Wrappable*>* visited_wrappables() {
return &visited_wrappables_;
}
@@ -169,13 +164,11 @@
WeakHeapObjectManager weak_object_manager_;
CachedWrapperMultiMap kept_alive_objects_;
scoped_ptr<ReferencedObjectMap> referenced_objects_;
- scoped_ptr<OpaqueRootTracker> opaque_root_tracker_;
CachedInterfaceData cached_interface_data_;
STLValueDeleter<CachedInterfaceData> cached_interface_data_deleter_;
ContextDestructor context_destructor_;
scoped_ptr<WrapperFactory> wrapper_factory_;
scoped_ptr<MozjsScriptValueFactory> script_value_factory_;
- scoped_ptr<OpaqueRootTracker::OpaqueRootState> opaque_root_state_;
JS::Heap<JSObject*> global_object_proxy_;
EnvironmentSettings* environment_settings_;
// TODO: Should be |std::unordered_set| once C++11 is enabled.
diff --git a/src/cobalt/script/mozjs/opaque_root_tracker.cc b/src/cobalt/script/mozjs/opaque_root_tracker.cc
deleted file mode 100644
index 2663e0b..0000000
--- a/src/cobalt/script/mozjs/opaque_root_tracker.cc
+++ /dev/null
@@ -1,143 +0,0 @@
-// 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/script/mozjs/opaque_root_tracker.h"
-
-#include <utility>
-#include <vector>
-
-#include "cobalt/script/mozjs/weak_heap_object.h"
-#include "third_party/mozjs/js/src/jsapi.h"
-
-namespace cobalt {
-namespace script {
-namespace mozjs {
-namespace {
-// Implementation of OpaqueRootTracker::OpaqueRootState.
-// On creation, this class will register reachability between objects and their
-// roots in |ReferencedObjectMap|. On destruction, the reachability
-// relationship will be removed.
-class OpaqueRootStateImpl : public OpaqueRootTracker::OpaqueRootState {
- public:
- OpaqueRootStateImpl(JSContext* context,
- ReferencedObjectMap* referenced_object_map)
- : context_(context), referenced_object_map_(referenced_object_map) {}
-
- void TrackReachability(WrapperPrivate* from, WrapperPrivate* to) {
- intptr_t from_key = ReferencedObjectMap::GetKeyForWrappable(
- from->wrappable<Wrappable>().get());
- JSObject* to_proxy = to->js_object_proxy();
- DCHECK(to_proxy);
- JS::RootedValue to_value(context_, JS::ObjectValue(*to_proxy));
- referenced_objects_.push_back(
- std::make_pair(from_key, WeakHeapObject(context_, to_value)));
- referenced_object_map_->AddReferencedObject(from_key, to_value);
- }
-
- ~OpaqueRootStateImpl() {
- JSAutoRequest auto_request(context_);
- for (ReferencedObjectPairVector::iterator it = referenced_objects_.begin();
- it != referenced_objects_.end(); ++it) {
- WeakHeapObject &value = it->second;
- if (value.IsGcThing() && !value.WasCollected()) {
- JS::RootedValue reachable_value(context_, value.GetValue());
- referenced_object_map_->RemoveReferencedObject(it->first,
- reachable_value);
- }
- }
- }
-
- private:
- typedef std::vector<std::pair<intptr_t, WeakHeapObject> >
- ReferencedObjectPairVector;
-
- JSContext* context_;
- ReferencedObjectMap* referenced_object_map_;
- ReferencedObjectPairVector referenced_objects_;
-};
-} // namespace
-
-OpaqueRootTracker::OpaqueRootTracker(JSContext* context,
- ReferencedObjectMap* referenced_object_map,
- WrapperFactory* wrapper_factory)
- : context_(context),
- referenced_object_map_(referenced_object_map),
- wrapper_factory_(wrapper_factory) {}
-
-void OpaqueRootTracker::AddObjectWithOpaqueRoot(
- WrapperPrivate* wrapper_private) {
- all_objects_.insert(wrapper_private);
-}
-
-void OpaqueRootTracker::RemoveObjectWithOpaqueRoot(
- WrapperPrivate* wrapper_private) {
- all_objects_.erase(wrapper_private);
-}
-
-scoped_ptr<OpaqueRootTracker::OpaqueRootState>
-OpaqueRootTracker::GetCurrentOpaqueRootState() {
- scoped_ptr<OpaqueRootStateImpl> state(
- new OpaqueRootStateImpl(context_, referenced_object_map_));
- // Get the current opaque root for all objects that are being tracked.
- for (WrapperPrivateSet::iterator it = all_objects_.begin();
- it != all_objects_.end(); ++it) {
- WrapperPrivate* wrapper_private = *it;
- TrackReachabilityToOpaqueRoot(state.get(), wrapper_private);
- TrackReachableWrappables(state.get(), wrapper_private);
- }
- return state.PassAs<OpaqueRootState>();
-}
-
-void OpaqueRootTracker::TrackReachabilityToOpaqueRoot(
- OpaqueRootState* state, WrapperPrivate* wrapper_private) {
- OpaqueRootStateImpl* state_impl =
- base::polymorphic_downcast<OpaqueRootStateImpl*>(state);
- // If this wrappable has an opaque root, track reachability between this
- // wrappable and its root.
- Wrappable* opaque_root = wrapper_private->GetOpaqueRoot();
- if (opaque_root) {
- WrapperPrivate* opaque_root_private = WrapperPrivate::GetFromWrappable(
- opaque_root, context_, wrapper_factory_);
- // Always mark the root as reachable from the non-root object.
- state_impl->TrackReachability(wrapper_private, opaque_root_private);
-
- // Only mark the non-root object as reachable if we need to keep the
- // wrapper alive for some reason. In general it's okay for a wrapper to
- // get GC'd because the Cobalt object will still be kept alive, and a new
- // JS object can be created if needed again.
- if (wrapper_private->ShouldKeepWrapperAliveIfReachable()) {
- state_impl->TrackReachability(opaque_root_private, wrapper_private);
- }
- }
-}
-
-void OpaqueRootTracker::TrackReachableWrappables(
- OpaqueRootState* state, WrapperPrivate* wrapper_private) {
- OpaqueRootStateImpl* state_impl =
- base::polymorphic_downcast<OpaqueRootStateImpl*>(state);
- // Track any wrappables that are explicitly marked as reachable from
- // this wrappable.
- typedef std::vector<Wrappable*> WrappableVector;
- WrappableVector reachable_objects;
- wrapper_private->GetReachableWrappables(&reachable_objects);
- for (size_t i = 0; i < reachable_objects.size(); ++i) {
- WrapperPrivate* reachable_object_private = WrapperPrivate::GetFromWrappable(
- reachable_objects[i], context_, wrapper_factory_);
- state_impl->TrackReachability(wrapper_private, reachable_object_private);
- }
-}
-
-} // namespace mozjs
-} // namespace script
-} // namespace cobalt
diff --git a/src/cobalt/script/mozjs/opaque_root_tracker.h b/src/cobalt/script/mozjs/opaque_root_tracker.h
deleted file mode 100644
index 2b3aade..0000000
--- a/src/cobalt/script/mozjs/opaque_root_tracker.h
+++ /dev/null
@@ -1,89 +0,0 @@
-// 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_SCRIPT_MOZJS_OPAQUE_ROOT_TRACKER_H_
-#define COBALT_SCRIPT_MOZJS_OPAQUE_ROOT_TRACKER_H_
-
-#include "base/hash_tables.h"
-#include "cobalt/script/mozjs/referenced_object_map.h"
-#include "cobalt/script/mozjs/wrapper_factory.h"
-#include "cobalt/script/mozjs/wrapper_private.h"
-
-namespace cobalt {
-namespace script {
-namespace mozjs {
-
-// This class manages lifetime of structures containing objects that are
-// reachable from through the interface implementation, but not through
-// JavaScript, by ensuring that the root of the structure is not garbage
-// collected if any of the members of the structure are reachable.
-//
-// The implementation of the structure in Cobalt is typically reference counted.
-// The |root| of that structure is a single node that transitively holds a
-// reference to every other node in the structure. It may be the case that the
-// only reference to that root node is from a JS object's WrapperPrivate. The
-// OpaqueRootTracker class ensures that if some node in the structure is
-// reachable from JavaScript, the JS object holding the reference to the root
-// of the structure is marked as reachable as well, which preserves the final
-// reference to the root of the structure, keeping the entire structure alive.
-//
-// For example, any DOM Node can be reached from any other DOM Node object in
-// the same tree. If an arbitary internal Node is reachable from JavaScript,
-// this class will ensure that the root of the tree will also be kept alive,
-// preserving the entire tree until no nodes in the tree are reachable from
-// JavaScript.
-//
-// An object's opaque root can change throughout the object's lifetime, so the
-// root needs to be recalculated every garbage collection phase.
-class OpaqueRootTracker {
- public:
- // Callers do not need to operate on this class. They just need to manage its
- // lifetime appropriately as described below.
- class OpaqueRootState {
- protected:
- OpaqueRootState() {}
- virtual ~OpaqueRootState() {}
- friend class scoped_ptr<OpaqueRootState>;
- };
-
- OpaqueRootTracker(JSContext* context,
- ReferencedObjectMap* referenced_object_map,
- WrapperFactory* wrapper_factory);
-
- // All objects that implement this functionality must be registered to this
- // class.
- void AddObjectWithOpaqueRoot(WrapperPrivate* wrapper_private);
- void RemoveObjectWithOpaqueRoot(WrapperPrivate* wrapper_private);
-
- // Get the current state of opaque roots. This should be called when garbage
- // collection begins before marking has begun. Once garbage collection is
- // complete, this should be released.
- scoped_ptr<OpaqueRootState> GetCurrentOpaqueRootState();
-
- private:
- void TrackReachabilityToOpaqueRoot(OpaqueRootState* state,
- WrapperPrivate* wrapper_private);
- void TrackReachableWrappables(OpaqueRootState* state,
- WrapperPrivate* wrapper_private);
- typedef base::hash_set<WrapperPrivate*> WrapperPrivateSet;
-
- JSContext* context_;
- ReferencedObjectMap* referenced_object_map_;
- WrapperFactory* wrapper_factory_;
- // list of objects that are potentially reachable from an opaque root
- WrapperPrivateSet all_objects_;
-};
-} // namespace mozjs
-} // namespace script
-} // namespace cobalt
-#endif // COBALT_SCRIPT_MOZJS_OPAQUE_ROOT_TRACKER_H_
diff --git a/src/cobalt/script/mozjs/wrapper_private.cc b/src/cobalt/script/mozjs/wrapper_private.cc
index 7b8d983..3814020 100644
--- a/src/cobalt/script/mozjs/wrapper_private.cc
+++ b/src/cobalt/script/mozjs/wrapper_private.cc
@@ -88,38 +88,13 @@
}
}
-Wrappable* WrapperPrivate::GetOpaqueRoot() const {
- if (!get_opaque_root_function_.is_null()) {
- return get_opaque_root_function_.Run(wrappable_);
- }
- return NULL;
-}
-
-void WrapperPrivate::GetReachableWrappables(
- std::vector<Wrappable*>* reachable) {
- if (!get_reachable_wrappables_function_.is_null()) {
- return get_reachable_wrappables_function_.Run(wrappable_, reachable);
- }
-}
-
-bool WrapperPrivate::ShouldKeepWrapperAliveIfReachable() {
- ProxyHandler* proxy_handler = base::polymorphic_downcast<ProxyHandler*>(
- js::GetProxyHandler(wrapper_proxy_));
- DCHECK(proxy_handler);
- return proxy_handler->has_custom_property() ||
- wrappable_->ShouldKeepWrapperAlive();
-}
-
// static
-void WrapperPrivate::AddPrivateData(
- JSContext* context, JS::HandleObject wrapper_proxy,
- const scoped_refptr<Wrappable>& wrappable,
- const GetOpaqueRootFunction& get_opaque_root_function,
- const GetReachableWrappablesFunction& get_reachable_wrappables_function) {
+void WrapperPrivate::AddPrivateData(JSContext* context,
+ JS::HandleObject wrapper_proxy,
+ const scoped_refptr<Wrappable>& wrappable) {
DCHECK(js::IsProxy(wrapper_proxy));
- WrapperPrivate* private_data = new WrapperPrivate(
- context, wrappable, wrapper_proxy, get_opaque_root_function,
- get_reachable_wrappables_function);
+ WrapperPrivate* private_data =
+ new WrapperPrivate(context, wrappable, wrapper_proxy);
JS::RootedObject target_object(context,
js::GetProxyTargetObject(wrapper_proxy));
JS_SetPrivate(target_object, private_data);
@@ -216,32 +191,14 @@
}
}
-WrapperPrivate::WrapperPrivate(
- JSContext* context, const scoped_refptr<Wrappable>& wrappable,
- JS::HandleObject wrapper_proxy,
- const GetOpaqueRootFunction& get_opaque_root_function,
- const GetReachableWrappablesFunction& get_reachable_wrappables_function)
- : context_(context),
- wrappable_(wrappable),
- wrapper_proxy_(wrapper_proxy),
- get_opaque_root_function_(get_opaque_root_function),
- get_reachable_wrappables_function_(get_reachable_wrappables_function) {
+WrapperPrivate::WrapperPrivate(JSContext* context,
+ const scoped_refptr<Wrappable>& wrappable,
+ JS::HandleObject wrapper_proxy)
+ : context_(context), wrappable_(wrappable), wrapper_proxy_(wrapper_proxy) {
DCHECK(js::IsProxy(wrapper_proxy));
- if (!get_opaque_root_function_.is_null() ||
- !get_reachable_wrappables_function_.is_null()) {
- MozjsGlobalEnvironment* global_environment =
- MozjsGlobalEnvironment::GetFromContext(context_);
- global_environment->opaque_root_tracker()->AddObjectWithOpaqueRoot(this);
- }
}
WrapperPrivate::~WrapperPrivate() {
- if (!get_opaque_root_function_.is_null() ||
- !get_reachable_wrappables_function_.is_null()) {
- MozjsGlobalEnvironment* global_environment =
- MozjsGlobalEnvironment::GetFromContext(context_);
- global_environment->opaque_root_tracker()->RemoveObjectWithOpaqueRoot(this);
- }
wrapper_proxy_ = NULL;
}
diff --git a/src/cobalt/script/mozjs/wrapper_private.h b/src/cobalt/script/mozjs/wrapper_private.h
index 1ac464f..5f15731 100644
--- a/src/cobalt/script/mozjs/wrapper_private.h
+++ b/src/cobalt/script/mozjs/wrapper_private.h
@@ -58,10 +58,6 @@
class WrapperPrivate : public base::SupportsWeakPtr<WrapperPrivate> {
public:
typedef std::vector<Wrappable*> WrappableVector;
- typedef base::Callback<Wrappable*(const scoped_refptr<Wrappable>&)>
- GetOpaqueRootFunction;
- typedef base::Callback<void(const scoped_refptr<Wrappable>&,
- WrappableVector*)> GetReachableWrappablesFunction;
template <typename T>
scoped_refptr<T> wrappable() const {
@@ -70,25 +66,9 @@
JSObject* js_object_proxy() const { return wrapper_proxy_; }
- Wrappable* GetOpaqueRoot() const;
- void GetReachableWrappables(std::vector<Wrappable*>* reachable);
-
- // Return true if the GC should avoid collecting this wrapper. Note that if
- // the wrapper is unreachable, it may still be collected.
- bool ShouldKeepWrapperAliveIfReachable();
-
// Create a new WrapperPrivate instance and associate it with the wrapper.
- static void AddPrivateData(
- JSContext* context, JS::HandleObject wrapper_proxy,
- const scoped_refptr<Wrappable>& wrappable,
- const GetOpaqueRootFunction& get_opaque_root_function,
- const GetReachableWrappablesFunction& get_reachable_wrappables_function);
-
static void AddPrivateData(JSContext* context, JS::HandleObject wrapper_proxy,
- const scoped_refptr<Wrappable>& wrappable) {
- AddPrivateData(context, wrapper_proxy, wrappable, GetOpaqueRootFunction(),
- GetReachableWrappablesFunction());
- }
+ const scoped_refptr<Wrappable>& wrappable);
// Return true if the object has wrapper private.
static bool HasWrapperPrivate(JSContext* context, JS::HandleObject object);
@@ -118,18 +98,13 @@
static void Trace(JSTracer* trace, JSObject* object);
private:
- WrapperPrivate(
- JSContext* context, const scoped_refptr<Wrappable>& wrappable,
- JS::HandleObject wrapper_proxy,
- const GetOpaqueRootFunction& get_opaque_root_function,
- const GetReachableWrappablesFunction& get_reachable_wrappables_function);
+ WrapperPrivate(JSContext* context, const scoped_refptr<Wrappable>& wrappable,
+ JS::HandleObject wrapper_proxy);
~WrapperPrivate();
JSContext* context_;
scoped_refptr<Wrappable> wrappable_;
JS::Heap<JSObject*> wrapper_proxy_;
- GetOpaqueRootFunction get_opaque_root_function_;
- GetReachableWrappablesFunction get_reachable_wrappables_function_;
friend Tracer;
};
diff --git a/src/cobalt/webdriver/execute_test.cc b/src/cobalt/webdriver/execute_test.cc
index 50018d8..2a2e852 100644
--- a/src/cobalt/webdriver/execute_test.cc
+++ b/src/cobalt/webdriver/execute_test.cc
@@ -18,10 +18,10 @@
#include "base/json/json_reader.h"
#include "base/run_loop.h"
#include "cobalt/dom/document.h"
+#include "cobalt/dom/testing/stub_window.h"
#include "cobalt/script/global_environment.h"
#include "cobalt/script/javascript_engine.h"
#include "cobalt/webdriver/script_executor.h"
-#include "cobalt/webdriver/testing/stub_window.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -62,7 +62,7 @@
class ScriptExecutorTest : public ::testing::Test {
protected:
void SetUp() OVERRIDE {
- stub_window_.reset(new testing::StubWindow());
+ stub_window_.reset(new dom::testing::StubWindow());
script_executor_ =
ScriptExecutor::Create(&element_mapping_, global_environment());
@@ -78,7 +78,7 @@
}
protected:
- scoped_ptr<testing::StubWindow> stub_window_;
+ scoped_ptr<dom::testing::StubWindow> stub_window_;
MockElementMapping element_mapping_;
scoped_refptr<ScriptExecutor> script_executor_;
};
diff --git a/src/cobalt/webdriver/webdriver.gyp b/src/cobalt/webdriver/webdriver.gyp
index e6b431b..64e7481 100644
--- a/src/cobalt/webdriver/webdriver.gyp
+++ b/src/cobalt/webdriver/webdriver.gyp
@@ -89,6 +89,7 @@
'dependencies': [
'<(DEPTH)/base/base.gyp:base',
'<(DEPTH)/cobalt/dom/dom.gyp:dom',
+ '<(DEPTH)/cobalt/dom/dom.gyp:dom_testing',
'<(DEPTH)/cobalt/speech/speech.gyp:speech',
'<(DEPTH)/net/net.gyp:http_server',
'copy_webdriver_data',
diff --git a/src/cobalt/websocket/close_event.h b/src/cobalt/websocket/close_event.h
index 2a23cad..43b7a79 100644
--- a/src/cobalt/websocket/close_event.h
+++ b/src/cobalt/websocket/close_event.h
@@ -30,13 +30,11 @@
: Event(type), was_clean_(true), code_(net::kWebSocketNormalClosure) {}
explicit CloseEvent(const std::string& type)
: Event(type), was_clean_(true), code_(net::kWebSocketNormalClosure) {}
- CloseEvent(const base::Token type,
- const cobalt::websocket::CloseEventInit& eventInitDict)
+ CloseEvent(const base::Token type, const CloseEventInit& eventInitDict)
: Event(type), was_clean_(true), code_(net::kWebSocketNormalClosure) {
InitializeFromCloseEventInit(eventInitDict);
}
- CloseEvent(const std::string& type,
- const cobalt::websocket::CloseEventInit& eventInitDict)
+ CloseEvent(const std::string& type, const CloseEventInit& eventInitDict)
: Event(type), was_clean_(true), code_(net::kWebSocketNormalClosure) {
InitializeFromCloseEventInit(eventInitDict);
}
diff --git a/src/cobalt/websocket/close_event.idl b/src/cobalt/websocket/close_event.idl
index 28023c1..425e0d2 100644
--- a/src/cobalt/websocket/close_event.idl
+++ b/src/cobalt/websocket/close_event.idl
@@ -12,9 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-// Copyright © 2015 W3C® (MIT, ERCIM, Keio, Beihang).
-// This software or document includes material copied from or derived from
-// The WebSocket API https://www.w3.org/TR/websockets/#event-definitions
+// https://www.w3.org/TR/websockets/#closeevent
[Constructor(DOMString type, optional CloseEventInit eventInitDict)]
interface CloseEvent : Event {
diff --git a/src/cobalt/websocket/close_event_init.idl b/src/cobalt/websocket/close_event_init.idl
index ccd1237..29805c0 100644
--- a/src/cobalt/websocket/close_event_init.idl
+++ b/src/cobalt/websocket/close_event_init.idl
@@ -12,12 +12,8 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-// Copyright © 2015 W3C® (MIT, ERCIM, Keio, Beihang).
-// This software or document includes material copied from or derived from
-// The WebSocket API https://www.w3.org/TR/websockets/#event-definitions
-
-// From:
// https://html.spec.whatwg.org/multipage/comms.html#the-closeevent-interfaces
+
dictionary CloseEventInit : EventInit {
boolean wasClean = false;
unsigned short code = 0;
diff --git a/src/cobalt/websocket/web_socket.idl b/src/cobalt/websocket/web_socket.idl
index b0d2127..f4efaab 100644
--- a/src/cobalt/websocket/web_socket.idl
+++ b/src/cobalt/websocket/web_socket.idl
@@ -12,11 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-/*
- * Copyright © 2015 W3C® (MIT, ERCIM, Keio, Beihang).
- * This software or document includes material copied from or derived from
- * The WebSocket API https://www.w3.org/TR/websockets/
- */
+// https://www.w3.org/TR/websockets/#the-websocket-interface
[
Constructor(DOMString url, optional DOMString protocols),
diff --git a/src/cobalt/websocket/websocket.gyp b/src/cobalt/websocket/websocket.gyp
index d13c46d..1c377ef 100644
--- a/src/cobalt/websocket/websocket.gyp
+++ b/src/cobalt/websocket/websocket.gyp
@@ -58,6 +58,7 @@
],
'dependencies': [
'websocket',
+ '<(DEPTH)/cobalt/dom/dom.gyp:dom',
'<(DEPTH)/cobalt/test/test.gyp:run_all_unittests',
'<(DEPTH)/googleurl/googleurl.gyp:googleurl',
'<(DEPTH)/testing/gmock.gyp:gmock',
diff --git a/src/cobalt/xhr/xml_http_request.cc b/src/cobalt/xhr/xml_http_request.cc
index 806c7c5..cd119d6 100644
--- a/src/cobalt/xhr/xml_http_request.cc
+++ b/src/cobalt/xhr/xml_http_request.cc
@@ -686,6 +686,13 @@
}
}
+void XMLHttpRequest::TraceMembers(script::Tracer* tracer) {
+ XMLHttpRequestEventTarget::TraceMembers(tracer);
+
+ tracer->Trace(upload_or_null());
+ tracer->Trace(response_array_buffer_or_null());
+}
+
XMLHttpRequest::~XMLHttpRequest() {
DCHECK(thread_checker_.CalledOnValidThread());
dom::GlobalStats::GetInstance()->Remove(this);
diff --git a/src/cobalt/xhr/xml_http_request.h b/src/cobalt/xhr/xml_http_request.h
index 5e10595..7a7f997 100644
--- a/src/cobalt/xhr/xml_http_request.h
+++ b/src/cobalt/xhr/xml_http_request.h
@@ -169,6 +169,8 @@
return response_array_buffer_.get();
}
+ void TraceMembers(script::Tracer* tracer) OVERRIDE;
+
friend std::ostream& operator<<(std::ostream& os, const XMLHttpRequest& xhr);
DEFINE_WRAPPABLE_TYPE(XMLHttpRequest);
diff --git a/src/cobalt/xhr/xml_http_request.idl b/src/cobalt/xhr/xml_http_request.idl
index 3b164d6..a95bfcd 100644
--- a/src/cobalt/xhr/xml_http_request.idl
+++ b/src/cobalt/xhr/xml_http_request.idl
@@ -17,7 +17,6 @@
[
Constructor,
ConstructorCallWith=EnvironmentSettings,
- AddOpaqueRoots=("upload_or_null","response_array_buffer_or_null"),
] interface XMLHttpRequest : XMLHttpRequestEventTarget {
// event handler
attribute EventHandler onreadystatechange;
diff --git a/src/cobalt/xhr/xml_http_request_event_target.cc b/src/cobalt/xhr/xml_http_request_event_target.cc
index 0bdd713..6ddc698 100644
--- a/src/cobalt/xhr/xml_http_request_event_target.cc
+++ b/src/cobalt/xhr/xml_http_request_event_target.cc
@@ -123,5 +123,10 @@
}
SetAttributeEventListener(base::Tokens::timeout(), listener);
}
+
+void XMLHttpRequestEventTarget::TraceMembers(script::Tracer* tracer) {
+ dom::EventTarget::TraceMembers(tracer);
+}
+
} // namespace xhr
} // namespace cobalt
diff --git a/src/cobalt/xhr/xml_http_request_event_target.h b/src/cobalt/xhr/xml_http_request_event_target.h
index a4f8c6d..9297eeb 100644
--- a/src/cobalt/xhr/xml_http_request_event_target.h
+++ b/src/cobalt/xhr/xml_http_request_event_target.h
@@ -43,6 +43,8 @@
void set_onprogress(const EventListenerScriptValue& listener);
void set_ontimeout(const EventListenerScriptValue& listener);
+ void TraceMembers(script::Tracer* tracer) OVERRIDE;
+
DEFINE_WRAPPABLE_TYPE(XMLHttpRequestEventTarget);
protected:
diff --git a/src/media/base/sbplayer_pipeline.cc b/src/media/base/sbplayer_pipeline.cc
index 044871c..aaaff86 100644
--- a/src/media/base/sbplayer_pipeline.cc
+++ b/src/media/base/sbplayer_pipeline.cc
@@ -326,6 +326,7 @@
if (!player_) {
seek_cb.Run(PIPELINE_ERROR_INVALID_STATE);
+ return;
}
player_->PrepareForSeek();
diff --git a/src/media/player/web_media_player_impl.cc b/src/media/player/web_media_player_impl.cc
index e1690a9..d6d920d 100644
--- a/src/media/player/web_media_player_impl.cc
+++ b/src/media/player/web_media_player_impl.cc
@@ -29,8 +29,12 @@
#include "media/filters/video_renderer_base.h"
#include "media/player/web_media_player_proxy.h"
+namespace media {
namespace {
+// Used to ensure that there is no more than one instance of WebMediaPlayerImpl.
+WebMediaPlayerImpl* s_instance;
+
// Limits the range of playback rate.
//
// TODO(kylep): Revisit these.
@@ -92,8 +96,6 @@
} // namespace
-namespace media {
-
#define BIND_TO_RENDER_LOOP(function) \
BindToLoop(main_loop_->message_loop_proxy(), \
base::Bind(function, AsWeakPtr()))
@@ -137,6 +139,9 @@
is_local_source_(false),
supports_save_(true),
suppress_destruction_errors_(false) {
+ DCHECK(!s_instance);
+ s_instance = this;
+
media_log_->AddEvent(
media_log_->CreateEvent(MediaLogEvent::WEBMEDIAPLAYER_CREATED));
@@ -181,6 +186,9 @@
WebMediaPlayerImpl::~WebMediaPlayerImpl() {
DCHECK(!main_loop_ || main_loop_ == MessageLoop::current());
+ DCHECK_EQ(s_instance, this);
+ s_instance = NULL;
+
if (delegate_) {
delegate_->UnregisterPlayer(this);
}
diff --git a/src/starboard/cryptography.h b/src/starboard/cryptography.h
index e9e2cab..8f700a9 100644
--- a/src/starboard/cryptography.h
+++ b/src/starboard/cryptography.h
@@ -25,18 +25,22 @@
// to maximize usage for SSL.
//
// 1. GCM - The preferred block cipher mode for OpenSSL, mainly due to speed.
-// 2. CBC - If GCM is disabled, then SSL will use the CBC stream cipher.
-// Normally this is less desirable because GCM is faster, but if CBC is
-// hardware-accelerated, it is likely to be better than software GCM. CBC
-// is also considered by some to be more secure.
-// 3. CTR - This can be used internally with GCM, as long as the CTR
-// implementation only uses the last 4 bytes of the IV for the counter.
-// (i.e. 96-bit IV, 32-bit counter)
-// 4. ECB - This is for if you only have core AES block encryption. It can be
-// used with any of the other cipher block modes to accelerate the core AES
-// algorithm if none of the streaming modes can be accelerated.
+// 2. CTR - This can be used internally with GCM, as long as the CTR
+// implementation only uses the last 4 bytes of the IV for the
+// counter. (i.e. 96-bit IV, 32-bit counter)
+// 3. ECB - This can be used (with a null IV) with any of the other cipher
+// block modes to accelerate the core AES algorithm if none of the
+// streaming modes can be accelerated.
+// 4. CBC - GCM is always preferred if the server and client both support
+// it. If not, they will generally negotiate down to AES-CBC. If this
+// happens, and CBC is supported by SbCryptography, then it will be
+// accelerated appropriately. But, most servers should support GCM,
+// so it is not likely to come up much, which is why it is the lowest
+// priority.
//
-// Further reading on GCM vs CBC vs CTR:
+// Further reading on block cipher modes:
+// https://en.wikipedia.org/wiki/Block_cipher_mode_of_operation
+// https://crbug.com/442572
// https://crypto.stackexchange.com/questions/10775/practical-disadvantages-of-gcm-mode-encryption
#ifndef STARBOARD_CRYPTOGRAPHY_H_
diff --git a/src/starboard/media.h b/src/starboard/media.h
index 3982d15..a58e369 100644
--- a/src/starboard/media.h
+++ b/src/starboard/media.h
@@ -359,7 +359,7 @@
SbMediaTransferId transfer;
// [Color Space field] The Matrix Coefficients of the video used to
- // derive luma and chroma values from reg, green, and blue color
+ // derive luma and chroma values from red, green, and blue color
// primaries. For clarity, the value and meanings for
// MatrixCoefficients are adopted from Table 4 of ISO/IEC
// 23001-8:2013/DCOR1. (0:GBR, 1: BT709, 2: Unspecified, 3:
@@ -368,14 +368,9 @@
// Luminance)
SbMediaMatrixId matrix;
- // [Color Space field] The Matrix Coefficients of the video used to
- // derive luma and chroma values from reg, green, and blue color
- // primaries. For clarity, the value and meanings for
- // MatrixCoefficients are adopted from Table 4 of ISO/IEC
- // 23001-8:2013/DCOR1. (0:GBR, 1: BT709, 2: Unspecified, 3:
- // Reserved, 4: FCC, 5: BT470BG, 6: SMPTE 170M, 7: SMPTE 240M, 8:
- // YCOCG, 9: BT2020 Non-constant Luminance, 10: BT2020 Constant
- // Luminance)
+ // [Color Space field] Clipping of the color ranges. (0:
+ // Unspecified, 1: Broadcast Range, 2: Full range (no clipping), 3:
+ // Defined by MatrixCoefficients/TransferCharacteristics)
SbMediaRangeId range;
// [Color Space field] Only used if primaries ==
diff --git a/src/starboard/shared/starboard/cryptography/cryptography_create_transformer.cc b/src/starboard/shared/starboard/cryptography/cryptography_create_transformer.cc
index 63b5a66..f38eea8 100644
--- a/src/starboard/shared/starboard/cryptography/cryptography_create_transformer.cc
+++ b/src/starboard/shared/starboard/cryptography/cryptography_create_transformer.cc
@@ -29,6 +29,7 @@
using starboard::shared::starboard::cryptography::Algorithm;
using starboard::shared::starboard::cryptography::kAlgorithmAes128Cbc;
using starboard::shared::starboard::cryptography::kAlgorithmAes128Ctr;
+using starboard::shared::starboard::cryptography::kAlgorithmAes128Ecb;
using starboard::shared::starboard::cryptography::kAlgorithmAes128Gcm;
SbCryptographyTransformer SbCryptographyCreateTransformer(
@@ -50,11 +51,35 @@
return kSbCryptographyInvalidTransformer;
}
- // TODO: Support 64-bit IV with CTR mode.
- if ((mode == kSbCryptographyBlockCipherModeGcm &&
- initialization_vector_size != 0) ||
- (mode != kSbCryptographyBlockCipherModeGcm &&
- initialization_vector_size != block_size_bits / 8)) {
+ Algorithm combined_algorithm;
+ if (mode == kSbCryptographyBlockCipherModeCbc) {
+ combined_algorithm = kAlgorithmAes128Cbc;
+ } else if (mode == kSbCryptographyBlockCipherModeCtr) {
+ combined_algorithm = kAlgorithmAes128Ctr;
+ } else if (mode == kSbCryptographyBlockCipherModeEcb) {
+ combined_algorithm = kAlgorithmAes128Ecb;
+ } else if (mode == kSbCryptographyBlockCipherModeGcm) {
+ combined_algorithm = kAlgorithmAes128Gcm;
+ } else {
+ SB_DLOG(WARNING) << "Unsupported block cipher mode: " << mode;
+ return kSbCryptographyInvalidTransformer;
+ }
+
+ if (mode == kSbCryptographyBlockCipherModeGcm ||
+ mode == kSbCryptographyBlockCipherModeEcb) {
+ if (initialization_vector_size != 0) {
+ SB_DLOG(WARNING) << "Unsupported initialization_vector_size: "
+ << initialization_vector_size;
+ return kSbCryptographyInvalidTransformer;
+ }
+ } else if (mode == kSbCryptographyBlockCipherModeCtr) {
+ if (initialization_vector_size != 0 && initialization_vector_size != 12 &&
+ initialization_vector_size != 16 && initialization_vector_size != 32) {
+ SB_DLOG(WARNING) << "Unsupported CTR initialization_vector_size: "
+ << initialization_vector_size;
+ return kSbCryptographyInvalidTransformer;
+ }
+ } else if (initialization_vector_size != block_size_bits / 8) {
SB_DLOG(WARNING) << "Unsupported initialization_vector_size: "
<< initialization_vector_size;
return kSbCryptographyInvalidTransformer;
@@ -65,22 +90,11 @@
return kSbCryptographyInvalidTransformer;
}
- Algorithm combined_algorithm;
- if (mode == kSbCryptographyBlockCipherModeCbc) {
- combined_algorithm = kAlgorithmAes128Cbc;
- } else if (mode == kSbCryptographyBlockCipherModeCtr) {
- combined_algorithm = kAlgorithmAes128Ctr;
- } else if (mode == kSbCryptographyBlockCipherModeGcm) {
- combined_algorithm = kAlgorithmAes128Gcm;
- } else {
- SB_DLOG(WARNING) << "Unsupported block cipher mode: " << mode;
- return kSbCryptographyInvalidTransformer;
- }
-
AES_KEY aeskey = {0};
int result = -1;
if (direction == kSbCryptographyDirectionDecode &&
mode != kSbCryptographyBlockCipherModeCtr &&
+ mode != kSbCryptographyBlockCipherModeEcb &&
mode != kSbCryptographyBlockCipherModeGcm) {
result = AES_set_decrypt_key(key, key_size * 8, &aeskey);
} else {
diff --git a/src/starboard/shared/starboard/cryptography/cryptography_set_initialization_vector.cc b/src/starboard/shared/starboard/cryptography/cryptography_set_initialization_vector.cc
index 0eb09a9..f81d293 100644
--- a/src/starboard/shared/starboard/cryptography/cryptography_set_initialization_vector.cc
+++ b/src/starboard/shared/starboard/cryptography/cryptography_set_initialization_vector.cc
@@ -12,8 +12,12 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-#include "starboard/configuration.h"
#include "starboard/cryptography.h"
+
+#include <algorithm>
+
+#include "starboard/configuration.h"
+#include "starboard/memory.h"
#include "starboard/shared/starboard/cryptography/cryptography_internal.h"
#include "starboard/shared/starboard/cryptography/software_aes.h"
@@ -23,17 +27,18 @@
using starboard::shared::starboard::cryptography::AES_gcm128_setiv;
using starboard::shared::starboard::cryptography::kAlgorithmAes128Gcm;
+using starboard::shared::starboard::cryptography::kAlgorithmAes128Ctr;
void SbCryptographySetInitializationVector(
SbCryptographyTransformer transformer,
const void* initialization_vector,
int initialization_vector_size) {
- if (transformer->algorithm != kAlgorithmAes128Gcm) {
- SB_DLOG(ERROR) << "Trying to set initialization vector on non-GCM "
- << "transformer.";
- return;
+ if (transformer->algorithm == kAlgorithmAes128Gcm) {
+ AES_gcm128_setiv(&transformer->gcm_context, &transformer->key,
+ initialization_vector, initialization_vector_size);
+ } else {
+ SbMemoryCopy(transformer->ivec, initialization_vector,
+ std::min(initialization_vector_size,
+ static_cast<int>(sizeof(transformer->ivec))));
}
-
- AES_gcm128_setiv(&transformer->gcm_context, &transformer->key,
- initialization_vector, initialization_vector_size);
}
diff --git a/src/starboard/shared/starboard/cryptography/cryptography_transform.cc b/src/starboard/shared/starboard/cryptography/cryptography_transform.cc
index 0981a63..bc78761 100644
--- a/src/starboard/shared/starboard/cryptography/cryptography_transform.cc
+++ b/src/starboard/shared/starboard/cryptography/cryptography_transform.cc
@@ -21,6 +21,17 @@
#error "SbCryptography requires SB_API_VERSION >= 4."
#endif
+using starboard::shared::starboard::cryptography::AES_cbc_encrypt;
+using starboard::shared::starboard::cryptography::AES_ctr128_encrypt;
+using starboard::shared::starboard::cryptography::AES_decrypt;
+using starboard::shared::starboard::cryptography::AES_encrypt;
+using starboard::shared::starboard::cryptography::AES_gcm128_decrypt;
+using starboard::shared::starboard::cryptography::AES_gcm128_encrypt;
+using starboard::shared::starboard::cryptography::kAlgorithmAes128Cbc;
+using starboard::shared::starboard::cryptography::kAlgorithmAes128Ctr;
+using starboard::shared::starboard::cryptography::kAlgorithmAes128Ecb;
+using starboard::shared::starboard::cryptography::kAlgorithmAes128Gcm;
+
int SbCryptographyTransform(SbCryptographyTransformer transformer,
const void* in_data,
int in_data_size,
@@ -33,32 +44,50 @@
return 0;
}
- if (transformer->algorithm ==
- starboard::shared::starboard::cryptography::kAlgorithmAes128Cbc) {
- int enc = transformer->direction == kSbCryptographyDirectionEncode
- ? SB_AES_ENCRYPT
- : SB_AES_DECRYPT;
- starboard::shared::starboard::cryptography::AES_cbc_encrypt(
- in_data, out_data, in_data_size, &(transformer->key), transformer->ivec,
- enc);
- } else if (transformer->algorithm ==
- starboard::shared::starboard::cryptography::kAlgorithmAes128Ctr) {
- starboard::shared::starboard::cryptography::AES_ctr128_encrypt(
- in_data, out_data, in_data_size, &(transformer->key), transformer->ivec,
- transformer->ecount_buf, &transformer->counter);
- } else if (transformer->algorithm ==
- starboard::shared::starboard::cryptography::kAlgorithmAes128Gcm) {
- if (transformer->direction == kSbCryptographyDirectionEncode) {
- starboard::shared::starboard::cryptography::AES_gcm128_encrypt(
- &transformer->gcm_context, &transformer->key, in_data, out_data,
- in_data_size);
- } else if (transformer->direction == kSbCryptographyDirectionDecode) {
- starboard::shared::starboard::cryptography::AES_gcm128_decrypt(
- &transformer->gcm_context, &transformer->key, in_data, out_data,
- in_data_size);
- } else {
+ switch (transformer->algorithm) {
+ case kAlgorithmAes128Cbc:
+ AES_cbc_encrypt(in_data, out_data, in_data_size, &(transformer->key),
+ transformer->ivec,
+ transformer->direction == kSbCryptographyDirectionEncode ?
+ SB_AES_ENCRYPT : SB_AES_DECRYPT);
+ break;
+
+ case kAlgorithmAes128Ctr:
+ AES_ctr128_encrypt(in_data, out_data, in_data_size, &(transformer->key),
+ transformer->ivec, transformer->ecount_buf,
+ &transformer->counter);
+ break;
+
+ case kAlgorithmAes128Ecb:
+ if (in_data_size % 16 != 0) {
+ SB_DLOG(ERROR) << "ECB called with a non-multiple of the block size.";
+ return -1;
+ }
+
+ if (transformer->direction == kSbCryptographyDirectionEncode) {
+ AES_encrypt(in_data, out_data, &transformer->key);
+ } else if (transformer->direction == kSbCryptographyDirectionDecode) {
+ AES_decrypt(in_data, out_data, &transformer->key);
+ } else {
+ SB_NOTREACHED();
+ }
+ break;
+
+ case kAlgorithmAes128Gcm:
+ if (transformer->direction == kSbCryptographyDirectionEncode) {
+ AES_gcm128_encrypt(&transformer->gcm_context, &transformer->key,
+ in_data, out_data, in_data_size);
+ } else if (transformer->direction == kSbCryptographyDirectionDecode) {
+ AES_gcm128_decrypt(&transformer->gcm_context, &transformer->key,
+ in_data, out_data, in_data_size);
+ } else {
+ SB_NOTREACHED();
+ }
+ break;
+
+ default:
SB_NOTREACHED();
- }
+ return -1;
}
return in_data_size;
diff --git a/src/starboard/shared/win32/application_stub.cc b/src/starboard/shared/uwp/application_uwp.cc
similarity index 68%
rename from src/starboard/shared/win32/application_stub.cc
rename to src/starboard/shared/uwp/application_uwp.cc
index 1f56080..9af9928 100644
--- a/src/starboard/shared/win32/application_stub.cc
+++ b/src/starboard/shared/uwp/application_uwp.cc
@@ -12,51 +12,51 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-#include "starboard/shared/win32/application_stub.h"
+#include "starboard/shared/uwp/application_uwp.h"
#include "starboard/event.h"
#include "starboard/log.h"
namespace starboard {
namespace shared {
-namespace win32 {
+namespace uwp {
-ApplicationStub::ApplicationStub() {
+ApplicationUwp::ApplicationUwp() {
SB_NOTIMPLEMENTED();
}
-ApplicationStub::~ApplicationStub() {
+ApplicationUwp::~ApplicationUwp() {
SB_NOTIMPLEMENTED();
}
-void ApplicationStub::Initialize() {
+void ApplicationUwp::Initialize() {
SB_NOTIMPLEMENTED();
}
-void ApplicationStub::Teardown() {
+void ApplicationUwp::Teardown() {
SB_NOTIMPLEMENTED();
}
-bool ApplicationStub::MayHaveSystemEvents() {
+bool ApplicationUwp::MayHaveSystemEvents() {
SB_NOTIMPLEMENTED();
return false;
}
-shared::starboard::Application::Event* ApplicationStub::PollNextSystemEvent() {
+shared::starboard::Application::Event* ApplicationUwp::PollNextSystemEvent() {
SB_NOTIMPLEMENTED();
return NULL;
}
shared::starboard::Application::Event*
-ApplicationStub::WaitForSystemEventWithTimeout(SbTime time) {
+ApplicationUwp::WaitForSystemEventWithTimeout(SbTime time) {
SB_NOTIMPLEMENTED();
return NULL;
}
-void ApplicationStub::WakeSystemEventWait() {
+void ApplicationUwp::WakeSystemEventWait() {
SB_NOTIMPLEMENTED();
}
-} // namespace win32
+} // namespace uwp
} // namespace shared
} // namespace starboard
diff --git a/src/starboard/shared/win32/application_stub.h b/src/starboard/shared/uwp/application_uwp.h
similarity index 75%
rename from src/starboard/shared/win32/application_stub.h
rename to src/starboard/shared/uwp/application_uwp.h
index c112677..437033a 100644
--- a/src/starboard/shared/win32/application_stub.h
+++ b/src/starboard/shared/uwp/application_uwp.h
@@ -12,8 +12,8 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-#ifndef STARBOARD_SHARED_WIN32_APPLICATION_STUB_H_
-#define STARBOARD_SHARED_WIN32_APPLICATION_STUB_H_
+#ifndef STARBOARD_SHARED_UWP_APPLICATION_UWP_H_
+#define STARBOARD_SHARED_UWP_APPLICATION_UWP_H_
#include "starboard/configuration.h"
#include "starboard/shared/internal_only.h"
@@ -23,16 +23,16 @@
namespace starboard {
namespace shared {
-namespace win32 {
+namespace uwp {
// Stub application engine using the generic queue and a stub implementation.
-class ApplicationStub : public shared::starboard::QueueApplication {
+class ApplicationUwp : public shared::starboard::QueueApplication {
public:
- ApplicationStub();
- ~ApplicationStub() SB_OVERRIDE;
+ ApplicationUwp();
+ ~ApplicationUwp() SB_OVERRIDE;
- static ApplicationStub* Get() {
- return static_cast<ApplicationStub*>(shared::starboard::Application::Get());
+ static ApplicationUwp* Get() {
+ return static_cast<ApplicationUwp*>(shared::starboard::Application::Get());
}
protected:
@@ -47,8 +47,8 @@
void WakeSystemEventWait() SB_OVERRIDE;
};
-} // namespace win32
+} // namespace uwp
} // namespace shared
} // namespace starboard
-#endif // STARBOARD_SHARED_WIN32_APPLICATION_STUB_H_
+#endif // STARBOARD_SHARED_UWP_APPLICATION_UWP_H_
diff --git a/src/starboard/shared/win32/atomic_public.h b/src/starboard/shared/win32/atomic_public.h
new file mode 100644
index 0000000..56088b3
--- /dev/null
+++ b/src/starboard/shared/win32/atomic_public.h
@@ -0,0 +1,238 @@
+// Copyright 2017 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef STARBOARD_SHARED_WIN32_ATOMIC_PUBLIC_H_
+#define STARBOARD_SHARED_WIN32_ATOMIC_PUBLIC_H_
+
+#include "starboard/atomic.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+// Declarations for Windows Intrinsic Functions
+// Defined here to avoid including Windows headers
+// See https://msdn.microsoft.com/en-us/library/w5405h95.aspx
+
+long _InterlockedCompareExchange(
+ long volatile * Destination,
+ long Exchange,
+ long Comparand
+);
+#pragma intrinsic(_InterlockedCompareExchange)
+
+__int64 _InterlockedCompareExchange64(
+ __int64 volatile * Destination,
+ __int64 Exchange,
+ __int64 Comparand
+);
+#pragma intrinsic(_InterlockedCompareExchange64)
+
+long _InterlockedExchange(
+ long volatile * Target,
+ long Value
+);
+#pragma intrinsic(_InterlockedExchange)
+
+__int64 _InterlockedExchange64(
+ __int64 volatile * Target,
+ __int64 Value
+);
+#pragma intrinsic(_InterlockedExchange64)
+
+long _InterlockedExchangeAdd(
+ long volatile * Addend,
+ long Value
+);
+#pragma intrinsic(_InterlockedExchangeAdd)
+
+__int64 _InterlockedExchangeAdd64(
+ __int64 volatile * Addend,
+ __int64 Value
+);
+#pragma intrinsic(_InterlockedExchangeAdd64)
+
+void _ReadWriteBarrier(void);
+#pragma intrinsic(_ReadWriteBarrier)
+
+SB_C_FORCE_INLINE SbAtomic32
+SbAtomicNoBarrier_CompareAndSwap(volatile SbAtomic32* ptr,
+ SbAtomic32 old_value,
+ SbAtomic32 new_value) {
+ // Note this does a full memory barrier
+ return _InterlockedCompareExchange(
+ (volatile long*) ptr, (long) new_value, (long) old_value);
+}
+
+SB_C_FORCE_INLINE SbAtomic32
+SbAtomicNoBarrier_Exchange(volatile SbAtomic32* ptr, SbAtomic32 new_value) {
+ // Note this does a full memory barrier
+ return _InterlockedExchange((volatile long*)ptr, (long)new_value);
+}
+
+SB_C_FORCE_INLINE SbAtomic32
+SbAtomicNoBarrier_Increment(volatile SbAtomic32* ptr, SbAtomic32 increment) {
+ return SbAtomicBarrier_Increment(ptr, increment);
+}
+
+SB_C_FORCE_INLINE SbAtomic32 SbAtomicBarrier_Increment(volatile SbAtomic32* ptr,
+ SbAtomic32 increment) {
+ // Note InterlockedExchangeAdd does a full memory barrier
+ return increment + _InterlockedExchangeAdd(
+ (volatile long *)ptr, (long)increment);
+}
+
+SB_C_FORCE_INLINE SbAtomic32
+SbAtomicAcquire_CompareAndSwap(volatile SbAtomic32* ptr,
+ SbAtomic32 old_value,
+ SbAtomic32 new_value) {
+ // Note this does a full memory barrier
+ return _InterlockedCompareExchange(
+ (volatile long*) ptr, (long) new_value, (long) old_value);
+}
+
+SB_C_FORCE_INLINE SbAtomic32
+SbAtomicRelease_CompareAndSwap(volatile SbAtomic32* ptr,
+ SbAtomic32 old_value,
+ SbAtomic32 new_value) {
+ // Note this does a full memory barrier
+ return _InterlockedCompareExchange(
+ (volatile long*) ptr, (long) new_value, (long) old_value);
+}
+
+// NOTE: https://msdn.microsoft.com/en-us/library/f20w0x5e.aspx
+// states _ReadWriteBarrier() is deprecated and
+// recommends "atomic_thread_fence", which is C++11 and violates
+// Starboard's "C-only header" policy
+SB_C_FORCE_INLINE void SbAtomicMemoryBarrier() {
+ _ReadWriteBarrier();
+}
+
+SB_C_FORCE_INLINE void SbAtomicNoBarrier_Store(volatile SbAtomic32* ptr,
+ SbAtomic32 value) {
+ *ptr = value;
+}
+
+SB_C_FORCE_INLINE void SbAtomicAcquire_Store(volatile SbAtomic32* ptr,
+ SbAtomic32 value) {
+ *ptr = value;
+ SbAtomicMemoryBarrier();
+}
+
+SB_C_FORCE_INLINE void SbAtomicRelease_Store(volatile SbAtomic32* ptr,
+ SbAtomic32 value) {
+ SbAtomicMemoryBarrier();
+ *ptr = value;
+}
+
+SB_C_FORCE_INLINE SbAtomic32
+SbAtomicNoBarrier_Load(volatile const SbAtomic32* ptr) {
+ return *ptr;
+}
+
+SB_C_FORCE_INLINE SbAtomic32
+SbAtomicAcquire_Load(volatile const SbAtomic32* ptr) {
+ SbAtomic32 value = *ptr;
+ SbAtomicMemoryBarrier();
+ return value;
+}
+
+SB_C_FORCE_INLINE SbAtomic32
+SbAtomicRelease_Load(volatile const SbAtomic32* ptr) {
+ SbAtomicMemoryBarrier();
+ return *ptr;
+}
+
+// 64-bit atomic operations (only available on 64-bit processors).
+#if SB_HAS(64_BIT_ATOMICS)
+SB_C_FORCE_INLINE SbAtomic64
+SbAtomicNoBarrier_CompareAndSwap64(volatile SbAtomic64* ptr,
+ SbAtomic64 old_value,
+ SbAtomic64 new_value) {
+ return _InterlockedCompareExchange64(ptr, new_value, old_value);
+}
+
+SB_C_FORCE_INLINE SbAtomic64
+SbAtomicNoBarrier_Exchange64(volatile SbAtomic64* ptr, SbAtomic64 new_value) {
+ return _InterlockedExchange64(ptr, new_value);
+}
+
+SB_C_FORCE_INLINE SbAtomic64
+SbAtomicNoBarrier_Increment64(volatile SbAtomic64* ptr, SbAtomic64 increment) {
+ return increment + _InterlockedExchangeAdd64(ptr, increment);
+}
+
+SB_C_FORCE_INLINE SbAtomic64
+SbAtomicBarrier_Increment64(volatile SbAtomic64* ptr, SbAtomic64 increment) {
+ // Note this does a full memory barrier
+ return increment + _InterlockedExchangeAdd64(ptr, increment);
+}
+
+SB_C_FORCE_INLINE SbAtomic64
+SbAtomicAcquire_CompareAndSwap64(volatile SbAtomic64* ptr,
+ SbAtomic64 old_value,
+ SbAtomic64 new_value) {
+ // Note this does a full memory barrier
+ return _InterlockedCompareExchange64(ptr, new_value, old_value);
+}
+
+SB_C_FORCE_INLINE SbAtomic64
+SbAtomicRelease_CompareAndSwap64(volatile SbAtomic64* ptr,
+ SbAtomic64 old_value,
+ SbAtomic64 new_value) {
+ // Note this does a full memory barrier
+ return _InterlockedCompareExchange64(ptr, new_value, old_value);
+}
+
+SB_C_FORCE_INLINE void SbAtomicNoBarrier_Store64(volatile SbAtomic64* ptr,
+ SbAtomic64 value) {
+ *ptr = value;
+}
+
+SB_C_FORCE_INLINE void SbAtomicAcquire_Store64(volatile SbAtomic64* ptr,
+ SbAtomic64 value) {
+ *ptr = value;
+ SbAtomicMemoryBarrier();
+}
+
+SB_C_FORCE_INLINE void SbAtomicRelease_Store64(volatile SbAtomic64* ptr,
+ SbAtomic64 value) {
+ SbAtomicMemoryBarrier();
+ *ptr = value;
+}
+
+SB_C_FORCE_INLINE SbAtomic64
+SbAtomicNoBarrier_Load64(volatile const SbAtomic64* ptr) {
+ return *ptr;
+}
+
+SB_C_FORCE_INLINE SbAtomic64
+SbAtomicAcquire_Load64(volatile const SbAtomic64* ptr) {
+ SbAtomic64 value = *ptr;
+ SbAtomicMemoryBarrier();
+ return value;
+}
+
+SB_C_FORCE_INLINE SbAtomic64
+SbAtomicRelease_Load64(volatile const SbAtomic64* ptr) {
+ SbAtomicMemoryBarrier();
+ return *ptr;
+}
+#endif // SB_HAS(64_BIT_ATOMICS)
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
+#endif // STARBOARD_SHARED_WIN32_ATOMIC_PUBLIC_H_
diff --git a/src/starboard/shared/win32/time_get_monotonic_thread_now.cc b/src/starboard/shared/win32/set_non_blocking_internal.cc
similarity index 62%
copy from src/starboard/shared/win32/time_get_monotonic_thread_now.cc
copy to src/starboard/shared/win32/set_non_blocking_internal.cc
index fff4bd9..35d74aa 100644
--- a/src/starboard/shared/win32/time_get_monotonic_thread_now.cc
+++ b/src/starboard/shared/win32/set_non_blocking_internal.cc
@@ -12,10 +12,20 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-#include "starboard/time.h"
+#include "starboard/shared/win32/set_non_blocking_internal.h"
-SbTimeMonotonic SbTimeGetMonotonicThreadNow() {
- // Neither QueryThreadCycleTime nor GetThreadTimes are listed as being
- // available in UWP.
- return SbTimeGetMonotonicNow();
+#include <winsock2.h>
+
+namespace starboard {
+namespace shared {
+namespace win32 {
+
+bool SetNonBlocking(SOCKET socket_handle) {
+ u_long kOne = 1;
+ bool success = (ioctlsocket(socket_handle, FIONBIO, &kOne) == 0);
+ return success;
}
+
+} // namespace win32
+} // namespace shared
+} // namespace starboard
diff --git a/src/starboard/shared/win32/set_non_blocking_internal.h b/src/starboard/shared/win32/set_non_blocking_internal.h
new file mode 100644
index 0000000..745a14b
--- /dev/null
+++ b/src/starboard/shared/win32/set_non_blocking_internal.h
@@ -0,0 +1,33 @@
+// Copyright 2017 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef STARBOARD_SHARED_WIN32_SET_NON_BLOCKING_INTERNAL_H_
+#define STARBOARD_SHARED_WIN32_SET_NON_BLOCKING_INTERNAL_H_
+
+#include "starboard/shared/internal_only.h"
+
+#include <winsock2.h>
+
+namespace starboard {
+namespace shared {
+namespace win32 {
+
+// Makes the socket file descriptor non-blocking.
+bool SetNonBlocking(SOCKET socket_handle);
+
+} // namespace win32
+} // namespace shared
+} // namespace starboard
+
+#endif // STARBOARD_SHARED_WIN32_SET_NON_BLOCKING_INTERNAL_H_
diff --git a/src/starboard/shared/win32/socket_accept.cc b/src/starboard/shared/win32/socket_accept.cc
new file mode 100644
index 0000000..08be946
--- /dev/null
+++ b/src/starboard/shared/win32/socket_accept.cc
@@ -0,0 +1,51 @@
+// Copyright 2017 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "starboard/socket.h"
+
+#include <winsock2.h>
+
+#include "starboard/log.h"
+#include "starboard/shared/win32/set_non_blocking_internal.h"
+#include "starboard/shared/win32/socket_internal.h"
+
+namespace sbwin32 = starboard::shared::win32;
+
+SbSocket SbSocketAccept(SbSocket socket) {
+ if (!SbSocketIsValid(socket)) {
+ return kSbSocketInvalid;
+ }
+
+ SB_DCHECK(socket->socket_handle != INVALID_SOCKET);
+
+ SOCKET socket_handle = accept(socket->socket_handle, nullptr, nullptr);
+ if (socket_handle == INVALID_SOCKET) {
+ socket->error = sbwin32::TranslateSocketErrorStatus(WSAGetLastError());
+ return kSbSocketInvalid;
+ }
+
+ // All Starboard sockets are non-blocking, so let's ensure it.
+ if (!sbwin32::SetNonBlocking(socket_handle)) {
+ // Something went wrong, we'll clean up and return failure.
+ socket->error = sbwin32::TranslateSocketErrorStatus(WSAGetLastError());
+ closesocket(socket_handle);
+ return kSbSocketInvalid;
+ }
+
+ socket->error = kSbSocketOk;
+
+ // Adopt the newly accepted socket.
+ return new SbSocketPrivate(socket->address_type, socket->protocol,
+ socket_handle);
+}
diff --git a/src/starboard/shared/win32/socket_bind.cc b/src/starboard/shared/win32/socket_bind.cc
new file mode 100644
index 0000000..9bc2afe
--- /dev/null
+++ b/src/starboard/shared/win32/socket_bind.cc
@@ -0,0 +1,76 @@
+// Copyright 2017 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "starboard/socket.h"
+
+#include <winsock2.h>
+
+#include "starboard/log.h"
+#include "starboard/memory.h"
+#include "starboard/shared/win32/socket_internal.h"
+
+namespace sbwin32 = starboard::shared::win32;
+
+namespace {
+
+bool IsIpv6InaddrAny(const SbSocketAddress* local_address) {
+ return SbMemoryIsZero(local_address->address, sbwin32::kAddressLengthIpv6);
+}
+
+} // namespace
+
+SbSocketError SbSocketBind(SbSocket socket,
+ const SbSocketAddress* local_address) {
+ if (!SbSocketIsValid(socket)) {
+ SB_DLOG(ERROR) << __FUNCTION__ << ": Invalid socket";
+ return kSbSocketErrorFailed;
+ }
+
+ sbwin32::SockAddr sock_addr;
+ if (!sock_addr.FromSbSocketAddress(local_address)) {
+ SB_DLOG(ERROR) << __FUNCTION__ << ": Invalid address";
+ return (socket->error = sbwin32::TranslateSocketErrorStatus(EINVAL));
+ }
+
+ SB_DCHECK(socket->socket_handle != INVALID_SOCKET);
+ if (local_address->type != socket->address_type) {
+ SB_DLOG(ERROR) << __FUNCTION__ << ": Incompatible addresses: "
+ << "socket type = " << socket->address_type
+ << ", argument type = " << local_address->type;
+ return (socket->error = sbwin32::TranslateSocketErrorStatus(EAFNOSUPPORT));
+ }
+
+ // When binding to the IPV6 any address, ensure that the IPV6_V6ONLY flag is
+ // off to allow incoming IPV4 connections on the same socket.
+ // See https://www.ietf.org/rfc/rfc3493.txt for details.
+ if (local_address && (local_address->type == kSbSocketAddressTypeIpv6) &&
+ IsIpv6InaddrAny(local_address)) {
+ if (!sbwin32::SetBooleanSocketOption(socket, IPPROTO_IPV6, IPV6_V6ONLY,
+ "IPV6_V6ONLY", false)) {
+ // Silently ignore errors, assume the default behavior is as expected.
+ socket->error = kSbSocketOk;
+ }
+ }
+
+ int result =
+ bind(socket->socket_handle, sock_addr.sockaddr(), sock_addr.length);
+ if (result == SOCKET_ERROR) {
+ int last_error = WSAGetLastError();
+ SB_DLOG(ERROR) << __FUNCTION__
+ << ": Bind failed. last_error=" << last_error;
+ return (socket->error = sbwin32::TranslateSocketErrorStatus(last_error));
+ }
+
+ return (socket->error = kSbSocketOk);
+}
diff --git a/src/starboard/shared/win32/time_get_monotonic_thread_now.cc b/src/starboard/shared/win32/socket_clear_last_error.cc
similarity index 72%
copy from src/starboard/shared/win32/time_get_monotonic_thread_now.cc
copy to src/starboard/shared/win32/socket_clear_last_error.cc
index fff4bd9..3c28d9b 100644
--- a/src/starboard/shared/win32/time_get_monotonic_thread_now.cc
+++ b/src/starboard/shared/win32/socket_clear_last_error.cc
@@ -12,10 +12,15 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-#include "starboard/time.h"
+#include "starboard/socket.h"
-SbTimeMonotonic SbTimeGetMonotonicThreadNow() {
- // Neither QueryThreadCycleTime nor GetThreadTimes are listed as being
- // available in UWP.
- return SbTimeGetMonotonicNow();
+#include "starboard/shared/win32/socket_internal.h"
+
+bool SbSocketClearLastError(SbSocket socket) {
+ if (!SbSocketIsValid(socket)) {
+ return false;
+ }
+
+ socket->error = kSbSocketOk;
+ return true;
}
diff --git a/src/starboard/shared/win32/socket_connect.cc b/src/starboard/shared/win32/socket_connect.cc
new file mode 100644
index 0000000..4287d48
--- /dev/null
+++ b/src/starboard/shared/win32/socket_connect.cc
@@ -0,0 +1,57 @@
+// Copyright 2017 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "starboard/socket.h"
+
+#include <winsock2.h>
+
+#include "starboard/log.h"
+#include "starboard/shared/win32/socket_internal.h"
+
+namespace sbwin32 = starboard::shared::win32;
+
+SbSocketError SbSocketConnect(SbSocket socket, const SbSocketAddress* address) {
+ if (!SbSocketIsValid(socket)) {
+ return kSbSocketErrorFailed;
+ }
+
+ sbwin32::SockAddr sock_addr;
+ if (!sock_addr.FromSbSocketAddress(address)) {
+ SB_DLOG(ERROR) << __FUNCTION__ << ": Invalid address";
+ return (socket->error = kSbSocketErrorFailed);
+ }
+
+ SB_DCHECK(socket->socket_handle != INVALID_SOCKET);
+ if (address->type != socket->address_type) {
+ SB_DLOG(ERROR) << __FUNCTION__ << ": Incompatible addresses: "
+ << "socket type = " << socket->address_type
+ << ", argument type = " << address->type;
+ return (socket->error = kSbSocketErrorFailed);
+ }
+
+ int result =
+ connect(socket->socket_handle, sock_addr.sockaddr(), sock_addr.length);
+
+ if (result != SOCKET_ERROR) {
+ return (socket->error = kSbSocketOk);
+ }
+
+ const int last_error = WSAGetLastError();
+ if (last_error == WSAEWOULDBLOCK) {
+ return (socket->error = kSbSocketPending);
+ }
+
+ SB_DLOG(ERROR) << __FUNCTION__ << ": connect failed: " << last_error;
+ return (socket->error = kSbSocketErrorFailed);
+}
diff --git a/src/starboard/shared/win32/socket_create.cc b/src/starboard/shared/win32/socket_create.cc
new file mode 100644
index 0000000..bc3a89c
--- /dev/null
+++ b/src/starboard/shared/win32/socket_create.cc
@@ -0,0 +1,118 @@
+// Copyright 2017 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "starboard/socket.h"
+
+#include <winsock2.h>
+#include <mswsock.h>
+
+#include "starboard/log.h"
+#include "starboard/shared/win32/set_non_blocking_internal.h"
+#include "starboard/shared/win32/socket_internal.h"
+
+namespace sbwin32 = starboard::shared::win32;
+
+SbSocket SbSocketCreate(SbSocketAddressType address_type,
+ SbSocketProtocol protocol) {
+ int socket_domain;
+ switch (address_type) {
+ case kSbSocketAddressTypeIpv4:
+ socket_domain = AF_INET;
+ break;
+ case kSbSocketAddressTypeIpv6:
+ socket_domain = AF_INET6;
+ break;
+ default:
+ SB_NOTREACHED();
+ return kSbSocketInvalid;
+ }
+
+ int socket_type;
+ int socket_protocol;
+ switch (protocol) {
+ case kSbSocketProtocolTcp:
+ socket_type = SOCK_STREAM;
+ socket_protocol = IPPROTO_TCP;
+ break;
+ case kSbSocketProtocolUdp:
+ socket_type = SOCK_DGRAM;
+ socket_protocol = IPPROTO_UDP;
+ break;
+ default:
+ SB_NOTREACHED();
+ return kSbSocketInvalid;
+ }
+
+ // WSASocket with dwFlags=0, instead of socket() creates sockets that do not
+ // support overlapped IO.
+ SOCKET socket_handle =
+ WSASocketW(socket_domain, socket_type, socket_protocol, nullptr, 0, 0);
+ if (socket_handle == INVALID_SOCKET) {
+ return kSbSocketInvalid;
+ }
+
+ // From
+ // https://msdn.microsoft.com/en-us/library/windows/desktop/cc136103(v=vs.85).aspx:
+ // "When the TargetOsVersion member is set to a value for Windows Vista or
+ // later, reductions to the TCP receive buffer size on this socket using the
+ // SO_RCVBUF socket option are allowed even after a TCP connection has been
+ // establishment."
+ // "When the TargetOsVersion member is set to a value for Windows Vista or
+ // later, receive window auto-tuning is enabled and the TCP window scale
+ // factor is reduced to 2 from the default value of 8."
+
+ // The main impetus for this change:
+
+ // "The WsaBehaviorAutoTuning option is needed on Windows Vista for some
+ // Internet gateway devices and firewalls that do not correctly support data
+ // flows for TCP connections that use the WSopt extension and a windows scale
+ // factor. On Windows Vista, a receiver by default negotiates a window scale
+ // factor of 8 for a maximum true window size of 16,776,960 bytes. When data
+ // begins to flow on a fast link, Windows initially starts with a 64 Kilobyte
+ // true window size by setting the Window field of the TCP header to 256 and
+ // setting the window scale factor to 8 in the TCP options (256*2^8=64KB).
+ // Some Internet gateway devices and firewalls ignore the window scale factor
+ // and only look at the advertised Window field in the TCP header specified as
+ // 256, and drop incoming packets for the connection that contain more than
+ // 256 bytes of TCP data. To support TCP receive window scaling, a gateway
+ // device or firewall must monitor the TCP handshake and track the negotiated
+ // window scale factor as part of the TCP connection data. Also some
+ // applications and TCP stack implementations on other platforms ignore the
+ // TCP WSopt extension and the window scaling factor. So the remote host
+ // sending the data may send data at the rate advertised in the Window field
+ // of the TCP header (256 bytes). This can result in data being received very
+ // slowly by the receiver."
+
+ if (protocol == kSbSocketProtocolTcp) {
+ WSA_COMPATIBILITY_MODE compatibility_mode = {WsaBehaviorAll, NTDDI_VISTA};
+
+ DWORD kZero = 0;
+ int return_value = WSAIoctl(
+ socket_handle, SIO_SET_COMPATIBILITY_MODE, &compatibility_mode,
+ sizeof(WSA_COMPATIBILITY_MODE), nullptr, 0, &kZero, nullptr, nullptr);
+ if (return_value == SOCKET_ERROR) {
+ closesocket(socket_handle);
+ return kSbSocketInvalid;
+ }
+ }
+
+ // All Starboard sockets are non-blocking, so let's ensure it.
+ if (!sbwin32::SetNonBlocking(socket_handle)) {
+ // Something went wrong, we'll clean up and return failure.
+ closesocket(socket_handle);
+ return kSbSocketInvalid;
+ }
+
+ return new SbSocketPrivate(address_type, protocol, socket_handle);
+}
diff --git a/src/starboard/shared/win32/socket_destroy.cc b/src/starboard/shared/win32/socket_destroy.cc
new file mode 100644
index 0000000..df47cae
--- /dev/null
+++ b/src/starboard/shared/win32/socket_destroy.cc
@@ -0,0 +1,39 @@
+// Copyright 2017 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "starboard/socket.h"
+
+#include <winsock2.h>
+
+#include "starboard/log.h"
+#include "starboard/shared/win32/socket_internal.h"
+#include "starboard/socket_waiter.h"
+
+bool SbSocketDestroy(SbSocket socket) {
+ if (!SbSocketIsValid(socket)) {
+ return false;
+ }
+
+ SB_DCHECK(socket->socket_handle != INVALID_SOCKET);
+
+ if (socket->waiter != nullptr) {
+ bool result = SbSocketWaiterRemove(socket->waiter, socket);
+ SB_DCHECK(result);
+ }
+
+ bool result = closesocket(socket->socket_handle) != SOCKET_ERROR;
+
+ delete socket;
+ return result;
+}
diff --git a/src/starboard/shared/win32/time_get_monotonic_thread_now.cc b/src/starboard/shared/win32/socket_free_resolution.cc
similarity index 70%
copy from src/starboard/shared/win32/time_get_monotonic_thread_now.cc
copy to src/starboard/shared/win32/socket_free_resolution.cc
index fff4bd9..212cde0 100644
--- a/src/starboard/shared/win32/time_get_monotonic_thread_now.cc
+++ b/src/starboard/shared/win32/socket_free_resolution.cc
@@ -12,10 +12,18 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-#include "starboard/time.h"
+#include "starboard/socket.h"
-SbTimeMonotonic SbTimeGetMonotonicThreadNow() {
- // Neither QueryThreadCycleTime nor GetThreadTimes are listed as being
- // available in UWP.
- return SbTimeGetMonotonicNow();
+#include "starboard/log.h"
+
+void SbSocketFreeResolution(SbSocketResolution* resolution) {
+ if (!resolution) {
+ return;
+ }
+
+ if (resolution->addresses) {
+ delete[] resolution->addresses;
+ }
+
+ delete resolution;
}
diff --git a/src/starboard/shared/win32/socket_get_interface_address.cc b/src/starboard/shared/win32/socket_get_interface_address.cc
new file mode 100644
index 0000000..a8f8b04
--- /dev/null
+++ b/src/starboard/shared/win32/socket_get_interface_address.cc
@@ -0,0 +1,342 @@
+// Copyright 2017 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "starboard/socket.h"
+
+#include <winsock2.h>
+
+#include <ifdef.h>
+#include <iphlpapi.h>
+
+#include <algorithm>
+#include <memory>
+
+#include "starboard/byte_swap.h"
+#include "starboard/log.h"
+#include "starboard/memory.h"
+#include "starboard/shared/win32/socket_internal.h"
+
+namespace sbwin32 = starboard::shared::win32;
+
+namespace {
+const ULONG kDefaultAdapterInfoBufferSizeInBytes = 16 * 1024;
+
+bool IsAnyAddress(const SbSocketAddress& address) {
+ switch (address.type) {
+ case kSbSocketAddressTypeIpv4:
+ return (address.address[0] == 0 && address.address[1] == 0 &&
+ address.address[2] == 0 && address.address[3] == 0);
+ case kSbSocketAddressTypeIpv6: {
+ bool found_nonzero = false;
+ for (std::size_t i = 0; i != sbwin32::kAddressLengthIpv6; ++i) {
+ found_nonzero |= (address.address[i] != 0);
+ }
+ return !found_nonzero;
+ }
+ default:
+ SB_NOTREACHED() << "Invalid address type " << address.type;
+ break;
+ }
+
+ return false;
+}
+
+void GenerateNetMaskFromPrefixLength(UINT8 prefix_length,
+ UINT32* const address_begin,
+ UINT32* const address_end) {
+ SB_DCHECK(address_end >= address_begin);
+ SB_DCHECK((reinterpret_cast<char*>(address_end) -
+ reinterpret_cast<char*>(address_begin)) %
+ 4 ==
+ 0);
+ UINT8 ones_left = prefix_length;
+ const int kBitsInOneDWORD = sizeof(UINT32) * 8;
+ for (UINT32* iterator = address_begin; iterator != address_end; ++iterator) {
+ UINT8 ones_in_this_dword = std::min<UINT8>(kBitsInOneDWORD, ones_left);
+ UINT64 mask_value =
+ kSbUInt64Max - ((1ULL << (kBitsInOneDWORD - ones_in_this_dword)) - 1);
+ *iterator =
+ SB_HOST_TO_NET_U32(static_cast<UINT32>(mask_value & kSbUInt64Max));
+ ones_left -= ones_in_this_dword;
+ }
+}
+
+bool PopulateInterfaceAddress(const IP_ADAPTER_UNICAST_ADDRESS& unicast_address,
+ SbSocketAddress* out_interface_ip) {
+ if (!out_interface_ip) {
+ return true;
+ }
+
+ const SOCKET_ADDRESS& address = unicast_address.Address;
+ sbwin32::SockAddr addr;
+ return addr.FromSockaddr(address.lpSockaddr) &&
+ addr.ToSbSocketAddress(out_interface_ip);
+}
+
+bool PopulateNetmask(const IP_ADAPTER_UNICAST_ADDRESS& unicast_address,
+ SbSocketAddress* out_netmask) {
+ if (!out_netmask) {
+ return true;
+ }
+
+ const SOCKET_ADDRESS& address = unicast_address.Address;
+ if (address.lpSockaddr == nullptr) {
+ return false;
+ }
+ const ADDRESS_FAMILY& family = address.lpSockaddr->sa_family;
+
+ switch (family) {
+ case AF_INET:
+ out_netmask->type = kSbSocketAddressTypeIpv4;
+ break;
+ case AF_INET6:
+ out_netmask->type = kSbSocketAddressTypeIpv6;
+ break;
+ default:
+ SB_NOTREACHED() << "Invalid family " << family;
+ return false;
+ }
+
+ UINT32* const begin_netmask =
+ reinterpret_cast<UINT32*>(&(out_netmask->address[0]));
+ UINT32* const end_netmask =
+ begin_netmask + SB_ARRAY_SIZE(out_netmask->address) / sizeof(UINT32);
+
+ GenerateNetMaskFromPrefixLength(unicast_address.OnLinkPrefixLength,
+ begin_netmask, end_netmask);
+ return true;
+}
+
+bool GetAdapters(const SbSocketAddressType address_type,
+ std::unique_ptr<char[]>* adapter_info) {
+ SB_DCHECK(adapter_info);
+
+ ULONG family = 0;
+ int address_length_bytes = 0;
+
+ switch (address_type) {
+ case kSbSocketAddressTypeIpv4:
+ family = AF_INET;
+ address_length_bytes = sbwin32::kAddressLengthIpv4;
+ break;
+ case kSbSocketAddressTypeIpv6:
+ family = AF_INET6;
+ address_length_bytes = sbwin32::kAddressLengthIpv6;
+ break;
+ default:
+ SB_NOTREACHED() << "Invalid address type.";
+ return false;
+ }
+
+ ULONG adapter_addresses_number_bytes = kDefaultAdapterInfoBufferSizeInBytes;
+
+ for (int try_count = 0; try_count != 2; ++try_count) {
+ // Using auto for return value here, since different versions of windows use
+ // slightly different datatypes. These differences do not matter to us, but
+ // the compiler might warn on them.
+ adapter_info->reset(new char[adapter_addresses_number_bytes]);
+ PIP_ADAPTER_ADDRESSES adapter_addresses =
+ reinterpret_cast<PIP_ADAPTER_ADDRESSES>(adapter_info->get());
+
+ // Note: If |GetAdapterAddresses| deems that buffer supplied is not enough,
+ // it will return the recommended number of bytes in
+ // |adapter_addresses_number_bytes|.
+ auto retval = GetAdaptersAddresses(
+ family, GAA_FLAG_SKIP_FRIENDLY_NAME | GAA_FLAG_SKIP_DNS_SERVER, nullptr,
+ adapter_addresses, &adapter_addresses_number_bytes);
+
+ if (retval == ERROR_SUCCESS) {
+ return true;
+ }
+ if (retval != ERROR_BUFFER_OVERFLOW) {
+ // Only retry with more memory if the error says so.
+ break;
+ }
+ SB_LOG(ERROR) << "GetAdapterAddresses() failed with error code " << retval;
+ }
+
+ return false;
+}
+
+bool GetNetmaskForInterfaceAddress(const SbSocketAddress& interface_address,
+ SbSocketAddress* out_netmask) {
+ std::unique_ptr<char[]> adapter_info_memory_block;
+ if (!GetAdapters(interface_address.type, &adapter_info_memory_block)) {
+ return false;
+ }
+ const void* const interface_address_buffer =
+ reinterpret_cast<const void* const>(interface_address.address);
+ for (PIP_ADAPTER_ADDRESSES adapter = reinterpret_cast<PIP_ADAPTER_ADDRESSES>(
+ adapter_info_memory_block.get());
+ adapter != nullptr; adapter = adapter->Next) {
+ if ((adapter->OperStatus != IfOperStatusUp) ||
+ (adapter->IfType != IF_TYPE_ETHERNET_CSMACD)) {
+ // Note: IfType == IF_TYPE_SOFTWARE_LOOPBACK is also skipped.
+ continue;
+ }
+
+ for (PIP_ADAPTER_UNICAST_ADDRESS unicast_address =
+ adapter->FirstUnicastAddress;
+ unicast_address != nullptr; unicast_address = unicast_address->Next) {
+ sbwin32::SockAddr addr;
+ if (!addr.FromSockaddr(unicast_address->Address.lpSockaddr)) {
+ continue;
+ }
+
+ const void* unicast_address_buffer = nullptr;
+ int bytes_to_check = 0;
+
+ switch (interface_address.type) {
+ case kSbSocketAddressTypeIpv4:
+ unicast_address_buffer =
+ reinterpret_cast<void*>(&(addr.sockaddr_in()->sin_addr));
+ bytes_to_check = sbwin32::kAddressLengthIpv4;
+ break;
+ case kSbSocketAddressTypeIpv6:
+ unicast_address_buffer =
+ reinterpret_cast<void*>(&(addr.sockaddr_in6()->sin6_addr));
+ bytes_to_check = sbwin32::kAddressLengthIpv6;
+ break;
+ default:
+ SB_DLOG(ERROR) << "Invalid interface address type "
+ << interface_address.type;
+ return false;
+ }
+
+ if (SbMemoryCompare(unicast_address_buffer, interface_address_buffer,
+ bytes_to_check) != 0) {
+ continue;
+ }
+
+ if (PopulateNetmask(*unicast_address, out_netmask)) {
+ return true;
+ }
+ }
+ }
+
+ return false;
+}
+
+bool IsUniqueLocalAddress(const unsigned char ip[16]) {
+ // Unique Local Addresses are in fd08::/8.
+ return ip[0] == 0xfd && ip[1] == 0x08;
+}
+
+bool FindInterfaceIP(const SbSocketAddressType address_type,
+ SbSocketAddress* out_interface_ip,
+ SbSocketAddress* out_netmask) {
+ if (out_interface_ip == nullptr) {
+ SB_NOTREACHED() << "out_interface_ip must be specified";
+ return false;
+ }
+
+ std::unique_ptr<char[]> adapter_info_memory_block;
+ if (!GetAdapters(address_type, &adapter_info_memory_block)) {
+ return false;
+ }
+
+ for (PIP_ADAPTER_ADDRESSES adapter = reinterpret_cast<PIP_ADAPTER_ADDRESSES>(
+ adapter_info_memory_block.get());
+ adapter != nullptr; adapter = adapter->Next) {
+ if ((adapter->OperStatus != IfOperStatusUp) ||
+ (adapter->IfType != IF_TYPE_ETHERNET_CSMACD)) {
+ // Note: IfType == IF_TYPE_SOFTWARE_LOOPBACK is also skipped.
+ continue;
+ }
+
+ for (PIP_ADAPTER_UNICAST_ADDRESS unicast_address =
+ adapter->FirstUnicastAddress;
+ unicast_address != nullptr; unicast_address = unicast_address->Next) {
+ if (unicast_address->Flags & (IP_ADAPTER_ADDRESS_TRANSIENT)) {
+ continue;
+ }
+ if (!(unicast_address->Flags & IP_ADAPTER_ADDRESS_DNS_ELIGIBLE)) {
+ continue;
+ }
+
+ // TODO: For IPv6, Prioritize interface with highest scope.
+ // Skip ULAs for now.
+ if (address_type == kSbSocketAddressTypeIpv6) {
+ // Documentation on MSDN states:
+ // "The SOCKADDR structure pointed to by the lpSockaddr member varies
+ // depending on the protocol or address family selected. For example,
+ // the sockaddr_in6 structure is used for an IPv6 socket address
+ // while the sockaddr_in4 structure is used for an IPv4 socket address."
+ // https://msdn.microsoft.com/en-us/library/windows/desktop/ms740507(v=vs.85).aspx
+
+ sockaddr_in6* addr = reinterpret_cast<sockaddr_in6*>(
+ unicast_address->Address.lpSockaddr);
+ SB_DCHECK(addr->sin6_family == AF_INET6);
+ if (IsUniqueLocalAddress(addr->sin6_addr.u.Byte)) {
+ continue;
+ }
+ }
+
+ if (!PopulateInterfaceAddress(*unicast_address, out_interface_ip)) {
+ continue;
+ }
+ if (!PopulateNetmask(*unicast_address, out_netmask)) {
+ continue;
+ }
+
+ return true;
+ }
+ }
+ return false;
+}
+
+bool FindSourceAddressForDestination(const SbSocketAddress& destination,
+ SbSocketAddress* out_source_address) {
+ SbSocket socket = SbSocketCreate(destination.type, kSbSocketProtocolUdp);
+ if (!SbSocketIsValid(socket)) {
+ return false;
+ }
+
+ SbSocketError connect_retval = SbSocketConnect(socket, &destination);
+ if (connect_retval != kSbSocketOk) {
+ bool socket_destroyed = SbSocketDestroy(socket);
+ SB_DCHECK(socket_destroyed);
+ return false;
+ }
+
+ bool success = SbSocketGetLocalAddress(socket, out_source_address);
+ bool socket_destroyed = SbSocketDestroy(socket);
+ SB_DCHECK(socket_destroyed);
+ return success;
+}
+
+} // namespace
+
+bool SbSocketGetInterfaceAddress(const SbSocketAddress* const destination,
+ SbSocketAddress* out_source_address,
+ SbSocketAddress* out_netmask) {
+ if (!out_source_address) {
+ return false;
+ }
+
+ if (destination == nullptr) {
+ // Return either a v4 or a v6 address. Per spec.
+ return (FindInterfaceIP(kSbSocketAddressTypeIpv4, out_source_address,
+ out_netmask) ||
+ FindInterfaceIP(kSbSocketAddressTypeIpv6, out_source_address,
+ out_netmask));
+ } else if (IsAnyAddress(*destination)) {
+ return FindInterfaceIP(destination->type, out_source_address, out_netmask);
+ } else {
+ return (FindSourceAddressForDestination(*destination, out_source_address) &&
+ GetNetmaskForInterfaceAddress(*out_source_address, out_netmask));
+ }
+
+ return false;
+}
diff --git a/src/starboard/shared/win32/time_get_monotonic_thread_now.cc b/src/starboard/shared/win32/socket_get_last_error.cc
similarity index 72%
copy from src/starboard/shared/win32/time_get_monotonic_thread_now.cc
copy to src/starboard/shared/win32/socket_get_last_error.cc
index fff4bd9..51d2e9a 100644
--- a/src/starboard/shared/win32/time_get_monotonic_thread_now.cc
+++ b/src/starboard/shared/win32/socket_get_last_error.cc
@@ -12,10 +12,14 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-#include "starboard/time.h"
+#include "starboard/socket.h"
-SbTimeMonotonic SbTimeGetMonotonicThreadNow() {
- // Neither QueryThreadCycleTime nor GetThreadTimes are listed as being
- // available in UWP.
- return SbTimeGetMonotonicNow();
+#include "starboard/shared/win32/socket_internal.h"
+
+SbSocketError SbSocketGetLastError(SbSocket socket) {
+ if (!SbSocketIsValid(socket)) {
+ return kSbSocketErrorFailed;
+ }
+
+ return socket->error;
}
diff --git a/src/starboard/shared/win32/socket_get_local_address.cc b/src/starboard/shared/win32/socket_get_local_address.cc
new file mode 100644
index 0000000..d49d5b0
--- /dev/null
+++ b/src/starboard/shared/win32/socket_get_local_address.cc
@@ -0,0 +1,46 @@
+// Copyright 2017 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "starboard/socket.h"
+
+#include <winsock2.h>
+
+#include "starboard/log.h"
+#include "starboard/shared/win32/socket_internal.h"
+
+namespace sbwin32 = starboard::shared::win32;
+
+bool SbSocketGetLocalAddress(SbSocket socket, SbSocketAddress* out_address) {
+ if (!SbSocketIsValid(socket)) {
+ return false;
+ }
+
+ SB_DCHECK(socket->socket_handle != INVALID_SOCKET);
+ sbwin32::SockAddr sock_addr;
+ int result = getsockname(socket->socket_handle, sock_addr.sockaddr(),
+ &sock_addr.length);
+ if (result == SOCKET_ERROR) {
+ int last_error = WSAGetLastError();
+ SB_LOG(ERROR) << "getsockname() failed with last_error = " << last_error;
+ socket->error = sbwin32::TranslateSocketErrorStatus(last_error);
+ return false;
+ }
+ if (!sock_addr.ToSbSocketAddress(out_address)) {
+ socket->error = kSbSocketErrorFailed;
+ return false;
+ }
+
+ socket->error = kSbSocketOk;
+ return true;
+}
diff --git a/src/starboard/shared/win32/socket_internal.cc b/src/starboard/shared/win32/socket_internal.cc
new file mode 100644
index 0000000..c81df3e
--- /dev/null
+++ b/src/starboard/shared/win32/socket_internal.cc
@@ -0,0 +1,193 @@
+// Copyright 2017 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "starboard/shared/win32/socket_internal.h"
+
+#include <winsock2.h>
+
+#include "starboard/log.h"
+#include "starboard/memory.h"
+
+namespace starboard {
+namespace shared {
+namespace win32 {
+
+namespace {
+const socklen_t kAddressStructLengthIpv4 =
+ static_cast<socklen_t>(sizeof(struct sockaddr_in));
+const socklen_t kAddressStructLengthIpv6 =
+ static_cast<socklen_t>(sizeof(struct sockaddr_in6));
+}
+
+SbSocketError TranslateSocketErrorStatus(int error) {
+ switch (error) {
+ case 0:
+ return kSbSocketOk;
+ case WSAEINPROGRESS:
+ case WSAEWOULDBLOCK:
+ return kSbSocketPending;
+ }
+
+ // Here's where we would be more nuanced if we need to be.
+ return kSbSocketErrorFailed;
+}
+
+bool SetBooleanSocketOption(SbSocket socket,
+ int level,
+ int option_code,
+ const char* option_name,
+ bool value) {
+ if (!SbSocketIsValid(socket)) {
+ return false;
+ }
+
+ SB_DCHECK(socket->socket_handle != INVALID_SOCKET);
+ const int on = value ? 1 : 0;
+ int result = setsockopt(socket->socket_handle, level, option_code,
+ reinterpret_cast<const char*>(&on), sizeof(on));
+ if (result == SOCKET_ERROR) {
+ int last_error = WSAGetLastError();
+ SB_DLOG(ERROR) << "Failed to set " << option_name << " on socket "
+ << socket->socket_handle << ", last_error = " << last_error;
+ socket->error = TranslateSocketErrorStatus(last_error);
+ return false;
+ }
+
+ socket->error = kSbSocketOk;
+ return true;
+}
+
+bool SetIntegerSocketOption(SbSocket socket,
+ int level,
+ int option_code,
+ const char* option_name,
+ int value) {
+ if (!SbSocketIsValid(socket)) {
+ return false;
+ }
+
+ SB_DCHECK(socket->socket_handle != INVALID_SOCKET);
+ int result = setsockopt(socket->socket_handle, level, option_code,
+ reinterpret_cast<const char*>(&value), sizeof(value));
+ if (result == SOCKET_ERROR) {
+ int last_error = WSAGetLastError();
+ SB_DLOG(ERROR) << "Failed to set " << option_name << " on socket "
+ << socket->socket_handle << ", last_error = " << last_error;
+ socket->error = TranslateSocketErrorStatus(last_error);
+ return false;
+ }
+
+ socket->error = kSbSocketOk;
+ return true;
+}
+
+bool SockAddr::FromSbSocketAddress(const SbSocketAddress* address) {
+ if (!address) {
+ return false;
+ }
+
+ length = sizeof(storage_);
+ switch (address->type) {
+ case kSbSocketAddressTypeIpv4: {
+ struct sockaddr_in* addr = sockaddr_in();
+ length = kAddressStructLengthIpv4;
+ SbMemorySet(addr, 0, length);
+ addr->sin_family = AF_INET;
+ addr->sin_port = htons(address->port);
+ SbMemoryCopy(&addr->sin_addr, address->address, kAddressLengthIpv4);
+ break;
+ }
+ case kSbSocketAddressTypeIpv6: {
+ struct sockaddr_in6* addr6 = sockaddr_in6();
+ length = kAddressStructLengthIpv6;
+ SbMemorySet(addr6, 0, length);
+ addr6->sin6_family = AF_INET6;
+ addr6->sin6_port = htons(address->port);
+ SbMemoryCopy(&addr6->sin6_addr, address->address, kAddressLengthIpv6);
+ break;
+ }
+ default:
+ SB_NOTREACHED() << "Unrecognized address type: " << address->type;
+ return false;
+ }
+
+ return true;
+}
+
+bool SockAddr::ToSbSocketAddress(SbSocketAddress* out_address) const {
+ if (!out_address) {
+ return false;
+ }
+
+// Check that we have been properly initialized.
+ SB_DCHECK(length == kAddressStructLengthIpv4 ||
+ length == kAddressStructLengthIpv6);
+
+ if (family() == AF_INET) {
+ const struct sockaddr_in* addr = sockaddr_in();
+ if (length < kAddressStructLengthIpv4) {
+ SB_NOTREACHED() << "Insufficient INET size: " << length;
+ return false;
+ }
+
+ SbMemoryCopy(out_address->address, &addr->sin_addr, kAddressLengthIpv4);
+ out_address->port = ntohs(addr->sin_port);
+ out_address->type = kSbSocketAddressTypeIpv4;
+ return true;
+ }
+
+ if (family() == AF_INET6) {
+ const struct sockaddr_in6* addr6 = sockaddr_in6();
+ if (length < kAddressStructLengthIpv6) {
+ SB_NOTREACHED() << "Insufficient INET6 size: " << length;
+ return false;
+ }
+
+ SbMemoryCopy(out_address->address, &addr6->sin6_addr, kAddressLengthIpv6);
+ out_address->port = ntohs(addr6->sin6_port);
+ out_address->type = kSbSocketAddressTypeIpv6;
+ return true;
+ }
+
+ SB_NOTREACHED() << "Unrecognized address family: " << family();
+ return false;
+}
+
+bool SockAddr::FromSockaddr(const struct sockaddr* sock_addr) {
+ if (!sock_addr) {
+ return false;
+ }
+
+ int family = sock_addr->sa_family;
+ if (family == AF_INET) {
+ const struct sockaddr_in* addr =
+ reinterpret_cast<const struct sockaddr_in*>(sock_addr);
+ *sockaddr_in() = *addr;
+ length = static_cast<socklen_t>(sizeof(*addr));
+ return true;
+ } else if (family == AF_INET6) {
+ const struct sockaddr_in6* addr =
+ reinterpret_cast<const struct sockaddr_in6*>(sock_addr);
+ *sockaddr_in6() = *addr;
+ length = static_cast<socklen_t>(sizeof(*addr));
+ return true;
+ }
+
+ SB_DLOG(WARNING) << "Unrecognized address family: " << family;
+ return false;
+}
+
+} // namespace win32
+} // namespace shared
+} // namespace starboard
diff --git a/src/starboard/shared/win32/socket_internal.h b/src/starboard/shared/win32/socket_internal.h
new file mode 100644
index 0000000..3a92e18
--- /dev/null
+++ b/src/starboard/shared/win32/socket_internal.h
@@ -0,0 +1,134 @@
+// Copyright 2017 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef STARBOARD_SHARED_WIN32_SOCKET_INTERNAL_H_
+#define STARBOARD_SHARED_WIN32_SOCKET_INTERNAL_H_
+
+#include <winsock2.h>
+#include <WS2tcpip.h>
+
+#include "starboard/shared/internal_only.h"
+#include "starboard/socket.h"
+#include "starboard/socket_waiter.h"
+#include "starboard/types.h"
+
+struct SbSocketPrivate {
+ SbSocketPrivate(SbSocketAddressType address_type,
+ SbSocketProtocol protocol,
+ SOCKET fd)
+ : address_type(address_type),
+ protocol(protocol),
+ socket_handle(fd),
+ error(kSbSocketOk),
+ waiter(kSbSocketWaiterInvalid) {}
+ ~SbSocketPrivate() {}
+
+ // The address domain of this socket, IPv4 or IPv6.
+ SbSocketAddressType address_type;
+
+ // The protocol of this socket, UDP or TCP.
+ SbSocketProtocol protocol;
+
+ // The file descriptor for this socket.
+ SOCKET socket_handle;
+
+ // The last error that occurred on this socket, or kSbSocketOk.
+ SbSocketError error;
+
+ // The waiter this socket is registered with, or kSbSocketWaiterInvalid.
+ SbSocketWaiter waiter;
+};
+
+namespace starboard {
+namespace shared {
+namespace win32 {
+
+const socklen_t kAddressLengthIpv4 = 4;
+const socklen_t kAddressLengthIpv6 = 16;
+
+// Translates an last_error from a socket call into an SbSocketError.
+SbSocketError TranslateSocketErrorStatus(int error);
+
+// Sets a boolean socket option, doing all appropriate checks.
+bool SetBooleanSocketOption(SbSocket socket,
+ int level,
+ int option_code,
+ const char* option_name,
+ bool value);
+
+// Sets an integer socket option, doing all appropriate checks.
+bool SetIntegerSocketOption(SbSocket socket,
+ int level,
+ int option_code,
+ const char* option_name,
+ int value);
+
+// A helper class for converting back and forth from sockaddrs, ugh.
+class SockAddr {
+ public:
+ SockAddr() : length(sizeof(storage_)) {}
+ ~SockAddr() {}
+
+ // Initializes this SockAddr with the given SbSocketAddress, overwriting
+ // anything any address previously held.
+ bool FromSbSocketAddress(const SbSocketAddress* address);
+
+ // Initializes the given SbSocketAddress with this SockAddr, which must have
+ // been previously initialized.
+ bool ToSbSocketAddress(SbSocketAddress* out_address) const;
+
+ // Initializes this SockAddr with |sock_addr|, assuming it is appropriately
+ // sized for its type.
+ bool FromSockaddr(const struct sockaddr* sock_addr);
+
+ // The sockaddr family. We only support INET and INET6.
+ u_short family() const { return sockaddr()->sa_family; }
+
+ struct sockaddr* sockaddr() {
+ return reinterpret_cast<struct sockaddr*>(&storage_);
+ }
+
+ const struct sockaddr* sockaddr() const {
+ return reinterpret_cast<const struct sockaddr*>(&storage_);
+ }
+
+ struct sockaddr_in* sockaddr_in() {
+ return reinterpret_cast<struct sockaddr_in*>(&storage_);
+ }
+
+ const struct sockaddr_in* sockaddr_in() const {
+ return reinterpret_cast<const struct sockaddr_in*>(&storage_);
+ }
+
+ struct sockaddr_in6* sockaddr_in6() {
+ return reinterpret_cast<struct sockaddr_in6*>(&storage_);
+ }
+
+ const struct sockaddr_in6* sockaddr_in6() const {
+ return reinterpret_cast<const struct sockaddr_in6*>(&storage_);
+ }
+
+ // Public on purpose, because it will be handy to be passed directly by
+ // reference into other functions.
+ socklen_t length;
+
+ private:
+ sockaddr_storage storage_;
+};
+
+} // namespace win32
+} // namespace shared
+} // namespace starboard
+
+#endif // STARBOARD_SHARED_WIN32_SOCKET_INTERNAL_H_
diff --git a/src/starboard/shared/win32/socket_is_connected.cc b/src/starboard/shared/win32/socket_is_connected.cc
new file mode 100644
index 0000000..76e982d
--- /dev/null
+++ b/src/starboard/shared/win32/socket_is_connected.cc
@@ -0,0 +1,41 @@
+// Copyright 2017 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "starboard/socket.h"
+
+#include <winsock2.h>
+
+#include "starboard/log.h"
+#include "starboard/shared/win32/socket_internal.h"
+
+bool SbSocketIsConnected(SbSocket socket) {
+ if (!SbSocketIsValid(socket)) {
+ return false;
+ }
+
+ SB_DCHECK(socket->socket_handle != INVALID_SOCKET);
+
+ // To tell if it is really connected, we peek a byte from the stream. We
+ // should get a byte back, or an EAGAIN/EWOULDBLOCK telling us the socket is
+ // waiting for data.
+ char c;
+ const int result = recv(socket->socket_handle, &c, 1, MSG_PEEK);
+ if (result == 0) {
+ // If the connection is closed, the return value is 0.
+ return false;
+ }
+
+ const int last_error = WSAGetLastError();
+ return (result > 0 || last_error == WSAEWOULDBLOCK);
+}
diff --git a/src/starboard/shared/win32/socket_is_connected_and_idle.cc b/src/starboard/shared/win32/socket_is_connected_and_idle.cc
new file mode 100644
index 0000000..d66c508
--- /dev/null
+++ b/src/starboard/shared/win32/socket_is_connected_and_idle.cc
@@ -0,0 +1,40 @@
+// Copyright 2017 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "starboard/socket.h"
+
+#include <winsock2.h>
+
+#include "starboard/log.h"
+#include "starboard/shared/win32/socket_internal.h"
+
+bool SbSocketIsConnectedAndIdle(SbSocket socket) {
+ if (!SbSocketIsValid(socket)) {
+ return false;
+ }
+
+ SB_DCHECK(socket->socket_handle != INVALID_SOCKET);
+
+ // To tell if it is really connected and idle, we peek a byte from the
+ // stream. We should get an EAGAIN/EWOULDBLOCK telling us the socket is
+ // waiting for data.
+ char c;
+ int rv = recv(socket->socket_handle, &c, 1, MSG_PEEK);
+ if (rv != SOCKET_ERROR) {
+ // Either not connected, or not idle.
+ return false;
+ }
+
+ return (WSAGetLastError() == WSAEWOULDBLOCK);
+}
diff --git a/src/starboard/shared/win32/socket_join_multicast_group.cc b/src/starboard/shared/win32/socket_join_multicast_group.cc
new file mode 100644
index 0000000..459fcbd
--- /dev/null
+++ b/src/starboard/shared/win32/socket_join_multicast_group.cc
@@ -0,0 +1,52 @@
+// Copyright 2017 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "starboard/socket.h"
+
+#include <winsock2.h>
+
+#include "starboard/log.h"
+#include "starboard/shared/win32/socket_internal.h"
+
+namespace sbwin32 = starboard::shared::win32;
+
+bool SbSocketJoinMulticastGroup(SbSocket socket,
+ const SbSocketAddress* address) {
+ if (!SbSocketIsValid(socket)) {
+ return false;
+ }
+
+ if (!address) {
+ return false;
+ }
+
+ SB_DCHECK(socket->socket_handle != INVALID_SOCKET);
+ ip_mreq imreq = {0};
+ IN_ADDR addr = *reinterpret_cast<const IN_ADDR*>(address->address);
+ imreq.imr_multiaddr.s_addr = addr.S_un.S_addr;
+ imreq.imr_interface.s_addr = INADDR_ANY;
+
+ int result = setsockopt(socket->socket_handle, IPPROTO_IP, IP_ADD_MEMBERSHIP,
+ reinterpret_cast<const char*>(&imreq), sizeof(imreq));
+ if (result == SOCKET_ERROR) {
+ int last_error = WSAGetLastError();
+ SB_DLOG(ERROR) << "Failed to IP_ADD_MEMBERSHIP on socket "
+ << socket->socket_handle << ", last_error = " << last_error;
+ socket->error = sbwin32::TranslateSocketErrorStatus(last_error);
+ return false;
+ }
+
+ socket->error = kSbSocketOk;
+ return true;
+}
diff --git a/src/starboard/shared/win32/socket_listen.cc b/src/starboard/shared/win32/socket_listen.cc
new file mode 100644
index 0000000..fb8de43
--- /dev/null
+++ b/src/starboard/shared/win32/socket_listen.cc
@@ -0,0 +1,39 @@
+// Copyright 2017 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "starboard/socket.h"
+
+#include <winsock2.h>
+
+#include "starboard/log.h"
+#include "starboard/shared/win32/socket_internal.h"
+
+namespace sbwin32 = starboard::shared::win32;
+
+SbSocketError SbSocketListen(SbSocket socket) {
+ if (!SbSocketIsValid(socket)) {
+ return kSbSocketErrorFailed;
+ }
+
+ SB_DCHECK(socket->socket_handle != INVALID_SOCKET);
+ // TODO: Determine if we need to specify a > 0 backlog. It can go up to
+ // SOMAXCONN according to the documentation. Several places in chromium
+ // specify the literal "10" with the comment "maybe dont allow any backlog?"
+ int result = listen(socket->socket_handle, 0);
+ if (result == SOCKET_ERROR) {
+ return (socket->error = sbwin32::TranslateSocketErrorStatus(result));
+ }
+
+ return (socket->error = kSbSocketOk);
+}
diff --git a/src/starboard/shared/win32/socket_receive_from.cc b/src/starboard/shared/win32/socket_receive_from.cc
new file mode 100644
index 0000000..e00f31f
--- /dev/null
+++ b/src/starboard/shared/win32/socket_receive_from.cc
@@ -0,0 +1,107 @@
+// Copyright 2017 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "starboard/socket.h"
+
+#include <winsock2.h>
+
+#include "starboard/log.h"
+#include "starboard/shared/win32/socket_internal.h"
+
+namespace sbwin32 = starboard::shared::win32;
+
+namespace {
+
+bool IsReportableErrno(int code) {
+ return (code != WSAEWOULDBLOCK && code != WSAECONNRESET);
+}
+
+} // namespace
+
+int SbSocketReceiveFrom(SbSocket socket,
+ char* out_data,
+ int data_size,
+ SbSocketAddress* out_source) {
+ const int kRecvFlags = 0;
+
+ if (!SbSocketIsValid(socket)) {
+ return -1;
+ }
+
+ SB_DCHECK(socket->socket_handle != INVALID_SOCKET);
+ if (socket->protocol == kSbSocketProtocolTcp) {
+ if (out_source) {
+ sbwin32::SockAddr sock_addr;
+ int result = getpeername(socket->socket_handle, sock_addr.sockaddr(),
+ &sock_addr.length);
+ if (result == SOCKET_ERROR) {
+ int last_error = WSAGetLastError();
+ SB_DLOG(ERROR) << __FUNCTION__
+ << ": getpeername failed, last_error = " << last_error;
+ socket->error = sbwin32::TranslateSocketErrorStatus(last_error);
+ return -1;
+ }
+
+ if (!sock_addr.ToSbSocketAddress(out_source)) {
+ SB_DLOG(FATAL) << __FUNCTION__ << ": Bad TCP source address.";
+ socket->error = kSbSocketErrorFailed;
+ return -1;
+ }
+ }
+
+ int bytes_read =
+ recv(socket->socket_handle, out_data, data_size, kRecvFlags);
+ if (bytes_read >= 0) {
+ socket->error = kSbSocketOk;
+ return static_cast<int>(bytes_read);
+ }
+
+ int last_error = WSAGetLastError();
+ if (IsReportableErrno(last_error) &&
+ socket->error != sbwin32::TranslateSocketErrorStatus(last_error)) {
+ SB_DLOG(ERROR) << "recv failed, last_error = " << last_error;
+ }
+ socket->error = sbwin32::TranslateSocketErrorStatus(last_error);
+ return -1;
+ } else if (socket->protocol == kSbSocketProtocolUdp) {
+ sbwin32::SockAddr sock_addr;
+ ssize_t bytes_read =
+ recvfrom(socket->socket_handle, out_data, data_size, kRecvFlags,
+ sock_addr.sockaddr(), &sock_addr.length);
+
+ if (bytes_read >= 0) {
+ if (out_source) {
+ if (!sock_addr.ToSbSocketAddress(out_source)) {
+ SB_DLOG(FATAL) << __FUNCTION__ << ": Bad UDP source address.";
+ socket->error = kSbSocketErrorFailed;
+ return -1;
+ }
+ }
+
+ socket->error = kSbSocketOk;
+ return static_cast<int>(bytes_read);
+ }
+
+ int last_error = WSAGetLastError();
+ if (last_error != WSAEWOULDBLOCK &&
+ socket->error != sbwin32::TranslateSocketErrorStatus(last_error)) {
+ SB_DLOG(ERROR) << "recvfrom failed, last_error = " << last_error;
+ }
+ socket->error = sbwin32::TranslateSocketErrorStatus(last_error);
+ return -1;
+ }
+
+ SB_NOTREACHED() << "Unrecognized protocol: " << socket->protocol;
+ return -1;
+}
diff --git a/src/starboard/shared/win32/socket_resolve.cc b/src/starboard/shared/win32/socket_resolve.cc
new file mode 100644
index 0000000..d2fef44
--- /dev/null
+++ b/src/starboard/shared/win32/socket_resolve.cc
@@ -0,0 +1,90 @@
+// Copyright 2017 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "starboard/socket.h"
+
+#include <winsock2.h>
+
+#include <memory>
+#include <vector>
+
+#include "starboard/log.h"
+#include "starboard/shared/win32/socket_internal.h"
+
+namespace sbwin32 = starboard::shared::win32;
+
+SbSocketResolution* SbSocketResolve(const char* hostname, int filters) {
+ struct addrinfo* ai = nullptr;
+ struct addrinfo hints = {0};
+
+ if (filters & kSbSocketResolveFilterIpv4) {
+ if (filters & kSbSocketResolveFilterIpv6) {
+ hints.ai_family = AF_UNSPEC;
+ } else {
+ hints.ai_family = AF_INET;
+ }
+ } else if (filters & kSbSocketResolveFilterIpv6) {
+ hints.ai_family = AF_INET6;
+ } else {
+ hints.ai_family = AF_UNSPEC;
+ }
+
+ hints.ai_flags = AI_ADDRCONFIG;
+ hints.ai_socktype = SOCK_STREAM;
+
+ // Actually make the call to get the data.
+ int err = getaddrinfo(hostname, nullptr, &hints, &ai);
+ if (err != 0 || ai == nullptr) {
+ SB_DLOG(ERROR) << "getaddrinfo failed. last_error: " << WSAGetLastError();
+ return nullptr;
+ }
+
+ int address_count = 0;
+ for (const auto* i = ai; i != nullptr; i = i->ai_next) {
+ ++address_count;
+ }
+
+ SbSocketResolution* result = new SbSocketResolution();
+
+ // Translate all the sockaddrs.
+ std::vector<sbwin32::SockAddr> sock_addrs;
+ sock_addrs.resize(address_count);
+
+ std::vector<bool> parsed;
+ parsed.resize(address_count);
+
+ int index = 0;
+ int skip = 0;
+ for (const auto *i = ai; i != nullptr; i = i->ai_next, ++index) {
+ // Skip over any addresses we can't parse.
+ parsed[index] = sock_addrs[index].FromSockaddr(i->ai_addr);
+ if (!parsed[index]) {
+ ++skip;
+ }
+ }
+
+ result->address_count = address_count - skip;
+ result->addresses = new SbSocketAddress[result->address_count];
+
+ int result_index = 0;
+ for (int i = 0; i < address_count; ++i) {
+ if (parsed[i] &&
+ sock_addrs[i].ToSbSocketAddress(&result->addresses[result_index])) {
+ ++result_index;
+ }
+ }
+
+ freeaddrinfo(ai);
+ return result;
+}
diff --git a/src/starboard/shared/win32/socket_send_to.cc b/src/starboard/shared/win32/socket_send_to.cc
new file mode 100644
index 0000000..36cdd8b
--- /dev/null
+++ b/src/starboard/shared/win32/socket_send_to.cc
@@ -0,0 +1,91 @@
+// Copyright 2017 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "starboard/socket.h"
+
+#include <winsock2.h>
+
+#include "starboard/log.h"
+#include "starboard/shared/win32/socket_internal.h"
+
+namespace sbwin32 = starboard::shared::win32;
+
+int SbSocketSendTo(SbSocket socket,
+ const char* data,
+ int data_size,
+ const SbSocketAddress* destination) {
+ const int kSendFlags = 0;
+ if (!SbSocketIsValid(socket)) {
+ return -1;
+ }
+
+ SB_DCHECK(socket->socket_handle != INVALID_SOCKET);
+ if (socket->protocol == kSbSocketProtocolTcp) {
+ if (destination) {
+ SB_DLOG(FATAL) << "Destination passed to TCP send.";
+ socket->error = kSbSocketErrorFailed;
+ return -1;
+ }
+
+ int bytes_written =
+ send(socket->socket_handle, data, data_size, kSendFlags);
+ if (bytes_written >= 0) {
+ socket->error = kSbSocketOk;
+ return static_cast<int>(bytes_written);
+ }
+
+ int last_error = WSAGetLastError();
+ if (last_error != EWOULDBLOCK) {
+ SB_DLOG(ERROR) << "send failed, last_error = " << last_error;
+ }
+ socket->error = sbwin32::TranslateSocketErrorStatus(last_error);
+ return -1;
+ } else if (socket->protocol == kSbSocketProtocolUdp) {
+ if (!destination) {
+ SB_DLOG(FATAL) << "No destination passed to UDP send.";
+ socket->error = kSbSocketErrorFailed;
+ return -1;
+ }
+
+ sbwin32::SockAddr sock_addr;
+ const sockaddr* sockaddr = nullptr;
+ socklen_t sockaddr_length = 0;
+ if (destination) {
+ if (!sock_addr.FromSbSocketAddress(destination)) {
+ SB_DLOG(FATAL) << "Invalid destination passed to UDP send.";
+ socket->error = kSbSocketErrorFailed;
+ return -1;
+ }
+ sockaddr = sock_addr.sockaddr();
+ sockaddr_length = sock_addr.length;
+ }
+
+ int bytes_written = sendto(socket->socket_handle, data, data_size,
+ kSendFlags, sockaddr, sockaddr_length);
+ if (bytes_written >= 0) {
+ socket->error = kSbSocketOk;
+ return static_cast<int>(bytes_written);
+ }
+
+ int last_error = WSAGetLastError();
+ if (last_error != WSAEWOULDBLOCK) {
+ SB_DLOG(ERROR) << "sendto failed, last_error = " << last_error;
+ }
+ socket->error = sbwin32::TranslateSocketErrorStatus(last_error);
+ return -1;
+ }
+
+ SB_NOTREACHED() << "Unrecognized protocol: " << socket->protocol;
+ return -1;
+}
diff --git a/src/starboard/shared/win32/time_get_monotonic_thread_now.cc b/src/starboard/shared/win32/socket_set_broadcast.cc
similarity index 63%
copy from src/starboard/shared/win32/time_get_monotonic_thread_now.cc
copy to src/starboard/shared/win32/socket_set_broadcast.cc
index fff4bd9..b60156b 100644
--- a/src/starboard/shared/win32/time_get_monotonic_thread_now.cc
+++ b/src/starboard/shared/win32/socket_set_broadcast.cc
@@ -12,10 +12,15 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-#include "starboard/time.h"
+#include "starboard/socket.h"
-SbTimeMonotonic SbTimeGetMonotonicThreadNow() {
- // Neither QueryThreadCycleTime nor GetThreadTimes are listed as being
- // available in UWP.
- return SbTimeGetMonotonicNow();
+#include <winsock2.h>
+
+#include "starboard/shared/win32/socket_internal.h"
+
+namespace sbwin32 = starboard::shared::win32;
+
+bool SbSocketSetBroadcast(SbSocket socket, bool value) {
+ return sbwin32::SetBooleanSocketOption(socket, SOL_SOCKET, SO_BROADCAST,
+ "SO_BROADCAST", value);
}
diff --git a/src/starboard/shared/win32/time_get_monotonic_thread_now.cc b/src/starboard/shared/win32/socket_set_receive_buffer_size.cc
similarity index 63%
copy from src/starboard/shared/win32/time_get_monotonic_thread_now.cc
copy to src/starboard/shared/win32/socket_set_receive_buffer_size.cc
index fff4bd9..61d108d 100644
--- a/src/starboard/shared/win32/time_get_monotonic_thread_now.cc
+++ b/src/starboard/shared/win32/socket_set_receive_buffer_size.cc
@@ -12,10 +12,15 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-#include "starboard/time.h"
+#include "starboard/socket.h"
-SbTimeMonotonic SbTimeGetMonotonicThreadNow() {
- // Neither QueryThreadCycleTime nor GetThreadTimes are listed as being
- // available in UWP.
- return SbTimeGetMonotonicNow();
+#include <winsock2.h>
+
+#include "starboard/shared/win32/socket_internal.h"
+
+namespace sbwin32 = starboard::shared::win32;
+
+bool SbSocketSetReceiveBufferSize(SbSocket socket, int32_t size) {
+ return sbwin32::SetIntegerSocketOption(socket, SOL_SOCKET, SO_RCVBUF,
+ "SO_RCVBUF", size);
}
diff --git a/src/starboard/shared/win32/time_get_monotonic_thread_now.cc b/src/starboard/shared/win32/socket_set_reuse_address.cc
similarity index 63%
copy from src/starboard/shared/win32/time_get_monotonic_thread_now.cc
copy to src/starboard/shared/win32/socket_set_reuse_address.cc
index fff4bd9..91145e6 100644
--- a/src/starboard/shared/win32/time_get_monotonic_thread_now.cc
+++ b/src/starboard/shared/win32/socket_set_reuse_address.cc
@@ -12,10 +12,15 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-#include "starboard/time.h"
+#include "starboard/socket.h"
-SbTimeMonotonic SbTimeGetMonotonicThreadNow() {
- // Neither QueryThreadCycleTime nor GetThreadTimes are listed as being
- // available in UWP.
- return SbTimeGetMonotonicNow();
+#include <winsock2.h>
+
+#include "starboard/shared/win32/socket_internal.h"
+
+namespace sbwin32 = starboard::shared::win32;
+
+bool SbSocketSetReuseAddress(SbSocket socket, bool value) {
+ return sbwin32::SetBooleanSocketOption(socket, SOL_SOCKET, SO_REUSEADDR,
+ "SO_REUSEADDR", value);
}
diff --git a/src/starboard/shared/win32/time_get_monotonic_thread_now.cc b/src/starboard/shared/win32/socket_set_send_buffer_size.cc
similarity index 63%
copy from src/starboard/shared/win32/time_get_monotonic_thread_now.cc
copy to src/starboard/shared/win32/socket_set_send_buffer_size.cc
index fff4bd9..2350e95 100644
--- a/src/starboard/shared/win32/time_get_monotonic_thread_now.cc
+++ b/src/starboard/shared/win32/socket_set_send_buffer_size.cc
@@ -12,10 +12,15 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-#include "starboard/time.h"
+#include "starboard/socket.h"
-SbTimeMonotonic SbTimeGetMonotonicThreadNow() {
- // Neither QueryThreadCycleTime nor GetThreadTimes are listed as being
- // available in UWP.
- return SbTimeGetMonotonicNow();
+#include <winsock2.h>
+
+#include "starboard/shared/win32/socket_internal.h"
+
+namespace sbwin32 = starboard::shared::win32;
+
+bool SbSocketSetSendBufferSize(SbSocket socket, int32_t size) {
+ return sbwin32::SetIntegerSocketOption(socket, SOL_SOCKET, SO_SNDBUF,
+ "SO_SNDBUF", size);
}
diff --git a/src/starboard/shared/win32/time_get_monotonic_thread_now.cc b/src/starboard/shared/win32/socket_set_tcp_keep_alive.cc
similarity index 60%
copy from src/starboard/shared/win32/time_get_monotonic_thread_now.cc
copy to src/starboard/shared/win32/socket_set_tcp_keep_alive.cc
index fff4bd9..aca24ef 100644
--- a/src/starboard/shared/win32/time_get_monotonic_thread_now.cc
+++ b/src/starboard/shared/win32/socket_set_tcp_keep_alive.cc
@@ -12,10 +12,17 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-#include "starboard/time.h"
+#include "starboard/socket.h"
-SbTimeMonotonic SbTimeGetMonotonicThreadNow() {
- // Neither QueryThreadCycleTime nor GetThreadTimes are listed as being
- // available in UWP.
- return SbTimeGetMonotonicNow();
+#include <winsock2.h>
+
+#include "starboard/shared/win32/socket_internal.h"
+
+namespace sbwin32 = starboard::shared::win32;
+
+bool SbSocketSetTcpKeepAlive(SbSocket socket, bool value, SbTime period) {
+ const DWORD should_set_keepalive = value;
+ bool result = sbwin32::SetBooleanSocketOption(
+ socket, SOL_SOCKET, SO_KEEPALIVE, "SO_KEEPALIVE", value);
+ return result;
}
diff --git a/src/starboard/shared/win32/time_get_monotonic_thread_now.cc b/src/starboard/shared/win32/socket_set_tcp_no_delay.cc
similarity index 63%
copy from src/starboard/shared/win32/time_get_monotonic_thread_now.cc
copy to src/starboard/shared/win32/socket_set_tcp_no_delay.cc
index fff4bd9..694d743 100644
--- a/src/starboard/shared/win32/time_get_monotonic_thread_now.cc
+++ b/src/starboard/shared/win32/socket_set_tcp_no_delay.cc
@@ -12,10 +12,15 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-#include "starboard/time.h"
+#include "starboard/socket.h"
-SbTimeMonotonic SbTimeGetMonotonicThreadNow() {
- // Neither QueryThreadCycleTime nor GetThreadTimes are listed as being
- // available in UWP.
- return SbTimeGetMonotonicNow();
+#include <winsock2.h>
+
+#include "starboard/shared/win32/socket_internal.h"
+
+namespace sbwin32 = starboard::shared::win32;
+
+bool SbSocketSetTcpNoDelay(SbSocket socket, bool value) {
+ return sbwin32::SetBooleanSocketOption(socket, IPPROTO_TCP, TCP_NODELAY,
+ "TCP_NODELAY", value);
}
diff --git a/src/starboard/shared/win32/socket_set_tcp_window_scaling.cc b/src/starboard/shared/win32/socket_set_tcp_window_scaling.cc
new file mode 100644
index 0000000..9a0e29a
--- /dev/null
+++ b/src/starboard/shared/win32/socket_set_tcp_window_scaling.cc
@@ -0,0 +1,44 @@
+// Copyright 2017 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "starboard/socket.h"
+
+#include <windows.h>
+#include <winsock2.h>
+
+// Note that windows.h and winsock2.h must be included before these.
+#include <mswsock.h>
+#include <sdkddkver.h>
+
+#include "starboard/shared/win32/socket_internal.h"
+
+bool SbSocketSetTcpWindowScaling(SbSocket socket, bool enable_window_scaling) {
+ // From
+ // https://msdn.microsoft.com/en-us/library/windows/desktop/cc136103(v=vs.85).aspx:
+ // "When the TargetOsVersion member is set to a value for Windows Vista or
+ // later, receive window auto-tuning is enabled and the TCP window scale
+ // factor is reduced to 2 from the default value of 8."
+
+ const ULONG target_os_version =
+ enable_window_scaling ? NTDDI_VISTA : NTDDI_WS03;
+ WSA_COMPATIBILITY_MODE compatibility_mode = {WsaBehaviorAutoTuning,
+ target_os_version};
+
+ DWORD kZero = 0;
+ int return_value = WSAIoctl(
+ socket->socket_handle, SIO_SET_COMPATIBILITY_MODE, &compatibility_mode,
+ sizeof(WSA_COMPATIBILITY_MODE), nullptr, 0, &kZero, nullptr, nullptr);
+
+ return return_value != SOCKET_ERROR;
+}
diff --git a/src/starboard/shared/win32/time_get_monotonic_now.cc b/src/starboard/shared/win32/time_get_monotonic_now.cc
index 56a162a..e761368 100644
--- a/src/starboard/shared/win32/time_get_monotonic_now.cc
+++ b/src/starboard/shared/win32/time_get_monotonic_now.cc
@@ -16,9 +16,32 @@
#include <windows.h>
-SbTimeMonotonic SbTimeGetMonotonicNow() {
- ULONGLONG result;
- QueryUnbiasedInterruptTimePrecise(&result);
+#include "starboard/log.h"
- return static_cast<SbTimeMonotonic>(result) / 10;
+SbTimeMonotonic SbTimeGetMonotonicNow() {
+ LARGE_INTEGER counts;
+ bool success;
+
+ success = QueryPerformanceCounter(&counts);
+
+ // "On systems that run Windows XP or later,
+ // the function will always succeed and will thus never return zero."
+ // https://msdn.microsoft.com/en-us/library/windows/desktop/ms644904(v=vs.85).aspx
+ SB_DCHECK(success);
+
+ LARGE_INTEGER countsPerSecond;
+ success = QueryPerformanceFrequency(&countsPerSecond);
+ // "On systems that run Windows XP or later,
+ // the function will always succeed and will thus never return zero."
+ // https://msdn.microsoft.com/en-us/library/windows/desktop/ms644905(v=vs.85).aspx
+ SB_DCHECK(success);
+
+ // An observed value of countsPerSecond on a desktop x86 machine is
+ // ~2.5e6. With this frequency, it will take ~37500 days to exceed
+ // 2^53, which is the mantissa precision of a double.
+ // Hence, we can safely convert to a double here without losing precision.
+ double result = static_cast<double>(counts.QuadPart);
+ result *= (1000.0 * 1000.0) / countsPerSecond.QuadPart;
+
+ return static_cast<SbTimeMonotonic>(result);
}
diff --git a/src/starboard/shared/win32/time_utils.h b/src/starboard/shared/win32/time_utils.h
index cad1368..fea9e12 100644
--- a/src/starboard/shared/win32/time_utils.h
+++ b/src/starboard/shared/win32/time_utils.h
@@ -53,7 +53,6 @@
inline DWORD ConvertSbTimeToMillisRoundUp(SbTime duration) {
const int64_t milliseconds_to_sleep =
(duration + kSbTimeMillisecond - 1) / kSbTimeMillisecond;
- SB_DCHECK(milliseconds_to_sleep <= kSbInt32Max);
return static_cast<DWORD>(milliseconds_to_sleep);
}
diff --git a/src/third_party/openssl/openssl/crypto/evp/e_aes.c b/src/third_party/openssl/openssl/crypto/evp/e_aes.c
index c81005f..fb0d026 100644
--- a/src/third_party/openssl/openssl/crypto/evp/e_aes.c
+++ b/src/third_party/openssl/openssl/crypto/evp/e_aes.c
@@ -118,18 +118,9 @@
case EVP_CIPH_CBC_MODE:
*mode = kSbCryptographyBlockCipherModeCbc;
return true;
- case EVP_CIPH_CFB_MODE:
- *mode = kSbCryptographyBlockCipherModeCfb;
- return true;
case EVP_CIPH_CTR_MODE:
*mode = kSbCryptographyBlockCipherModeCtr;
return true;
- case EVP_CIPH_ECB_MODE:
- *mode = kSbCryptographyBlockCipherModeEcb;
- return true;
- case EVP_CIPH_OFB_MODE:
- *mode = kSbCryptographyBlockCipherModeOfb;
- return true;
default:
break;
}
@@ -145,6 +136,14 @@
return SbCryptographyIsTransformerValid(context->gcm_transformer);
}
+static inline bool sb_gcm_has_ctr_stream(GCM128_CONTEXT *context) {
+ return SbCryptographyIsTransformerValid(context->ctr_transformer);
+}
+
+static inline bool sb_gcm_has_ecb_stream(GCM128_CONTEXT *context) {
+ return SbCryptographyIsTransformerValid(context->ecb_transformer);
+}
+
static int sb_init_key(EVP_CIPHER_CTX* context,
const unsigned char* key,
const unsigned char* initialization_vector,
@@ -187,27 +186,75 @@
return (result == len);
}
-static bool sb_gcm_init(GCM128_CONTEXT *context, const void *key, int key_length,
- int encrypt) {
+static inline SbCryptographyTransformer sb_create_ctr128(
+ SbCryptographyDirection direction, const void *key, int key_length) {
+ return SbCryptographyCreateTransformer(
+ kSbCryptographyAlgorithmAes,
+ 128,
+ direction,
+ kSbCryptographyBlockCipherModeCtr,
+ NULL,
+ 0,
+ key,
+ key_length);
+}
+
+static inline SbCryptographyTransformer sb_create_ecb128(
+ SbCryptographyDirection direction, const void *key, int key_length) {
+ return SbCryptographyCreateTransformer(
+ kSbCryptographyAlgorithmAes,
+ 128,
+ direction,
+ kSbCryptographyBlockCipherModeEcb,
+ NULL,
+ 0,
+ key,
+ key_length);
+}
+
+static inline SbCryptographyTransformer sb_create_gcm128(
+ SbCryptographyDirection direction, const void *key, int key_length) {
+ return SbCryptographyCreateTransformer(
+ kSbCryptographyAlgorithmAes,
+ 128,
+ direction,
+ kSbCryptographyBlockCipherModeGcm,
+ NULL,
+ 0,
+ key,
+ key_length);
+}
+
+static bool sb_gcm_init(GCM128_CONTEXT *context, const void *key,
+ int key_length, int encrypt) {
+ context->ctr_transformer = kSbCryptographyInvalidTransformer;
+ context->ecb_transformer = kSbCryptographyInvalidTransformer;
+ context->encrypt = encrypt;
+ context->raw_key_length = key_length;
+ SbMemoryCopy(context->raw_key, key, key_length);
+
SbCryptographyDirection direction =
(encrypt ? kSbCryptographyDirectionEncode :
kSbCryptographyDirectionDecode);
- context->gcm_transformer =
- SbCryptographyCreateTransformer(
- kSbCryptographyAlgorithmAes,
- 128,
- direction,
- kSbCryptographyBlockCipherModeGcm,
- NULL,
- 0,
- key,
- key_length);
- return sb_gcm_has_stream(context);
+ context->gcm_transformer = sb_create_gcm128(direction, key, key_length);
+ if (sb_gcm_has_stream(context)) {
+ return true;
+ }
+
+ return false;
}
-static inline void sb_gcm_setiv(GCM128_CONTEXT *context,
- const unsigned char *initialization_vector,
- size_t initialization_vector_size) {
+static void sb_gcm_init_backup(GCM128_CONTEXT *context, const void *key,
+ int key_length) {
+ context->ctr_transformer = sb_create_ctr128(kSbCryptographyDirectionEncode,
+ key, key_length);
+ context->ecb_transformer = sb_create_ecb128(kSbCryptographyDirectionEncode,
+ key, key_length);
+}
+
+static void sb_gcm_setiv(GCM128_CONTEXT *context,
+ const unsigned char *initialization_vector,
+ size_t initialization_vector_size) {
if (sb_gcm_has_stream(context)) {
SbCryptographySetInitializationVector(context->gcm_transformer,
initialization_vector,
@@ -230,7 +277,7 @@
return CRYPTO_gcm128_aad(context, data, data_size);
}
-static inline int sb_gcm_encrypt(GCM128_CONTEXT *context,
+static inline int sb_gcm_encrypt(GCM128_CONTEXT *context, ctr128_f ctr,
const unsigned char *in, unsigned char *out,
size_t len) {
if (sb_gcm_has_stream(context)) {
@@ -239,10 +286,13 @@
return result == len ? 0 : -1;
}
+ if (ctr || sb_gcm_has_ctr_stream(context)) {
+ return CRYPTO_gcm128_encrypt_ctr32(context, in, out, len, ctr);
+ }
return CRYPTO_gcm128_encrypt(context, in, out, len);
}
-static inline int sb_gcm_decrypt(GCM128_CONTEXT *context,
+static inline int sb_gcm_decrypt(GCM128_CONTEXT *context, ctr128_f ctr,
const unsigned char *in, unsigned char *out,
size_t len) {
if (sb_gcm_has_stream(context)) {
@@ -251,6 +301,9 @@
return result == len ? 0 : -1;
}
+ if (ctr || sb_gcm_has_ctr_stream(context)) {
+ return CRYPTO_gcm128_decrypt_ctr32(context, in, out, len, ctr);
+ }
return CRYPTO_gcm128_decrypt(context, in, out, len);
}
@@ -295,11 +348,22 @@
return false;
}
+static inline bool sb_gcm_has_ctr_stream(GCM128_CONTEXT *context) {
+ return false;
+}
+
+static inline bool sb_gcm_has_ecb_stream(GCM128_CONTEXT *context) {
+ return false;
+}
+
static bool sb_gcm_init(GCM128_CONTEXT *context, const void *key, int key_length,
int encrypt) {
return false;
}
+static void sb_gcm_init_backup(GCM128_CONTEXT *context, const void *key,
+ int key_length) {}
+
static inline void sb_gcm_setiv(GCM128_CONTEXT *context,
const unsigned char *initialization_vector,
size_t initialization_vector_size) {
@@ -313,15 +377,21 @@
return CRYPTO_gcm128_aad(context, data, data_size);
}
-static inline int sb_gcm_encrypt(GCM128_CONTEXT *context,
+static inline int sb_gcm_encrypt(GCM128_CONTEXT *context, ctr128_f ctr,
const unsigned char *in, unsigned char *out,
size_t len) {
+ if (ctr) {
+ return CRYPTO_gcm128_encrypt_ctr32(context, in, out, len, ctr);
+ }
return CRYPTO_gcm128_encrypt(context, in, out, len);
}
-static inline int sb_gcm_decrypt(GCM128_CONTEXT *context,
+static inline int sb_gcm_decrypt(GCM128_CONTEXT *context, ctr128_f ctr,
const unsigned char *in, unsigned char *out,
size_t len) {
+ if (ctr) {
+ return CRYPTO_gcm128_decrypt_ctr32(context, in, out, len, ctr);
+ }
return CRYPTO_gcm128_decrypt(context, in, out, len);
}
@@ -1076,6 +1146,7 @@
CRYPTO_gcm128_init(&gctx->gcm, &gctx->ks,
(block128_f) AES_encrypt);
gctx->ctr = (ctr128_f) bsaes_ctr32_encrypt_blocks;
+ sb_gcm_init_backup(&gctx->gcm, key, ctx->key_len);
}
break;
} else
@@ -1087,6 +1158,7 @@
CRYPTO_gcm128_init(&gctx->gcm, &gctx->ks,
(block128_f) vpaes_encrypt);
gctx->ctr = NULL;
+ sb_gcm_init_backup(&gctx->gcm, key, ctx->key_len);
}
break;
} else
@@ -1102,6 +1174,7 @@
# else
gctx->ctr = NULL;
# endif
+ sb_gcm_init_backup(&gctx->gcm, key, ctx->key_len);
}
} while (0);
@@ -1139,6 +1212,7 @@
{
EVP_AES_GCM_CTX *gctx = ctx->cipher_data;
int rv = -1;
+
/* Encrypt/decrypt must be performed in place */
if (out != in
|| len < (EVP_GCM_TLS_EXPLICIT_IV_LEN + EVP_GCM_TLS_TAG_LEN))
@@ -1160,28 +1234,16 @@
len -= EVP_GCM_TLS_EXPLICIT_IV_LEN + EVP_GCM_TLS_TAG_LEN;
if (ctx->encrypt) {
/* Encrypt payload */
- if (gctx->ctr) {
- if (CRYPTO_gcm128_encrypt_ctr32(&gctx->gcm,
- in, out, len, gctx->ctr))
- goto err;
- } else {
- if (sb_gcm_encrypt(&gctx->gcm, in, out, len))
- goto err;
- }
+ if (sb_gcm_encrypt(&gctx->gcm, gctx->ctr, in, out, len))
+ goto err;
out += len;
/* Finally write tag */
sb_gcm_tag(&gctx->gcm, out, EVP_GCM_TLS_TAG_LEN);
rv = len + EVP_GCM_TLS_EXPLICIT_IV_LEN + EVP_GCM_TLS_TAG_LEN;
} else {
/* Decrypt */
- if (gctx->ctr) {
- if (CRYPTO_gcm128_decrypt_ctr32(&gctx->gcm,
- in, out, len, gctx->ctr))
- goto err;
- } else {
- if (sb_gcm_decrypt(&gctx->gcm, in, out, len))
- goto err;
- }
+ if (sb_gcm_decrypt(&gctx->gcm, gctx->ctr, in, out, len))
+ goto err;
/* Retrieve tag */
sb_gcm_tag(&gctx->gcm, ctx->buf, EVP_GCM_TLS_TAG_LEN);
/* If tag mismatch wipe buffer */
@@ -1216,23 +1278,11 @@
if (sb_gcm_aad(&gctx->gcm, in, len))
return -1;
} else if (ctx->encrypt) {
- if (gctx->ctr) {
- if (CRYPTO_gcm128_encrypt_ctr32(&gctx->gcm,
- in, out, len, gctx->ctr))
- return -1;
- } else {
- if (sb_gcm_encrypt(&gctx->gcm, in, out, len))
- return -1;
- }
+ if (sb_gcm_encrypt(&gctx->gcm, gctx->ctr, in, out, len))
+ return -1;
} else {
- if (gctx->ctr) {
- if (CRYPTO_gcm128_decrypt_ctr32(&gctx->gcm,
- in, out, len, gctx->ctr))
- return -1;
- } else {
- if (sb_gcm_decrypt(&gctx->gcm, in, out, len))
- return -1;
- }
+ if (sb_gcm_decrypt(&gctx->gcm, gctx->ctr, in, out, len))
+ return -1;
}
return len;
} else {
diff --git a/src/third_party/openssl/openssl/crypto/modes/gcm128.c b/src/third_party/openssl/openssl/crypto/modes/gcm128.c
index cacc123..1df77da 100644
--- a/src/third_party/openssl/openssl/crypto/modes/gcm128.c
+++ b/src/third_party/openssl/openssl/crypto/modes/gcm128.c
@@ -86,6 +86,62 @@
} \
} while(0)
+
+#if defined(OPENSSL_SYS_STARBOARD) && SB_API_VERSION >= 4
+static const int kBlockSizeBits = 128;
+static const int kBlockSizeBytes = 16;
+static inline void sb_block128(GCM128_CONTEXT *ctx,
+ block128_f block,
+ const unsigned char in[16],
+ unsigned char out[16],
+ const void *key) {
+ if (SbCryptographyIsTransformerValid(ctx->ecb_transformer)) {
+ int result = SbCryptographyTransform(ctx->ecb_transformer, in,
+ kBlockSizeBytes, out);
+ SB_DCHECK(result == kBlockSizeBytes);
+ } else {
+ (*block)(in, out, key);
+ }
+}
+
+static inline void sb_ctr128(GCM128_CONTEXT *ctx,
+ ctr128_f ctr,
+ const unsigned char *in,
+ unsigned char *out,
+ size_t blocks,
+ const void *key,
+ const unsigned char ivec[16]) {
+ if (SbCryptographyIsTransformerValid(ctx->ctr_transformer)) {
+ SbCryptographySetInitializationVector(ctx->ctr_transformer, ivec, 16);
+ int len = (int)(blocks) * kBlockSizeBytes;
+ int result = SbCryptographyTransform(ctx->ctr_transformer, in, len, out);
+ SB_DCHECK(result == len);
+ } else {
+ (*ctr)(in, out, blocks, key, ivec);
+ }
+}
+#else // defined(OPENSSL_SYS_STARBOARD) && SB_API_VERSION >= 4
+static inline void sb_block128(GCM128_CONTEXT *ctx,
+ block128_f block,
+ const unsigned char in[16],
+ unsigned char out[16],
+ const void *key) {
+ SB_UNREFERENCED_PARAMETER(ctx);
+ (*block)(in, out, key);
+}
+
+static inline void sb_ctr128(GCM128_CONTEXT *ctx,
+ ctr128_f ctr,
+ const unsigned char *in,
+ unsigned char *out,
+ size_t blocks,
+ const void *key,
+ const unsigned char ivec[16]) {
+ SB_UNREFERENCED_PARAMETER(ctx);
+ (*ctr)(in, out, blocks, key, ivec);
+}
+#endif // defined(OPENSSL_SYS_STARBOARD) && SB_API_VERSION >= 4
+
/*-
* Even though permitted values for TABLE_BITS are 8, 4 and 1, it should
* never be set to 8. 8 is effectively reserved for testing purposes.
@@ -749,7 +805,7 @@
ctx->block = block;
ctx->key = key;
- (*block) (ctx->H.c, ctx->H.c, key);
+ sb_block128(ctx, block, ctx->H.c, ctx->H.c, key);
if (is_endian.little) {
/* H is stored in host byte order */
@@ -882,7 +938,7 @@
ctr = ctx->Yi.d[3];
}
- (*ctx->block) (ctx->Yi.c, ctx->EK0.c, ctx->key);
+ sb_block128(ctx, ctx->block, ctx->Yi.c, ctx->EK0.c, ctx->key);
++ctr;
if (is_endian.little)
#ifdef BSWAP4
@@ -1030,7 +1086,7 @@
size_t *out_t = (size_t *)out;
const size_t *in_t = (const size_t *)in;
- (*block) (ctx->Yi.c, ctx->EKi.c, key);
+ sb_block128(ctx, block, ctx->Yi.c, ctx->EKi.c, key);
++ctr;
if (is_endian.little)
# ifdef BSWAP4
@@ -1056,7 +1112,7 @@
size_t *out_t = (size_t *)out;
const size_t *in_t = (const size_t *)in;
- (*block) (ctx->Yi.c, ctx->EKi.c, key);
+ sb_block128(ctx, block, ctx->Yi.c, ctx->EKi.c, key);
++ctr;
if (is_endian.little)
# ifdef BSWAP4
@@ -1079,7 +1135,7 @@
size_t *out_t = (size_t *)out;
const size_t *in_t = (const size_t *)in;
- (*block) (ctx->Yi.c, ctx->EKi.c, key);
+ sb_block128(ctx, block, ctx->Yi.c, ctx->EKi.c, key);
++ctr;
if (is_endian.little)
# ifdef BSWAP4
@@ -1098,7 +1154,7 @@
}
# endif
if (len) {
- (*block) (ctx->Yi.c, ctx->EKi.c, key);
+ sb_block128(ctx, block, ctx->Yi.c, ctx->EKi.c, key);
++ctr;
if (is_endian.little)
# ifdef BSWAP4
@@ -1121,7 +1177,7 @@
#endif
for (i = 0; i < len; ++i) {
if (n == 0) {
- (*block) (ctx->Yi.c, ctx->EKi.c, key);
+ sb_block128(ctx, *block, ctx->Yi.c, ctx->EKi.c, key);
++ctr;
if (is_endian.little)
#ifdef BSWAP4
@@ -1217,7 +1273,7 @@
size_t *out_t = (size_t *)out;
const size_t *in_t = (const size_t *)in;
- (*block) (ctx->Yi.c, ctx->EKi.c, key);
+ sb_block128(ctx, block, ctx->Yi.c, ctx->EKi.c, key);
++ctr;
if (is_endian.little)
# ifdef BSWAP4
@@ -1241,7 +1297,7 @@
size_t *out_t = (size_t *)out;
const size_t *in_t = (const size_t *)in;
- (*block) (ctx->Yi.c, ctx->EKi.c, key);
+ sb_block128(ctx, block, ctx->Yi.c, ctx->EKi.c, key);
++ctr;
if (is_endian.little)
# ifdef BSWAP4
@@ -1263,7 +1319,7 @@
size_t *out_t = (size_t *)out;
const size_t *in_t = (const size_t *)in;
- (*block) (ctx->Yi.c, ctx->EKi.c, key);
+ sb_block128(ctx, block, ctx->Yi.c, ctx->EKi.c, key);
++ctr;
if (is_endian.little)
# ifdef BSWAP4
@@ -1285,7 +1341,7 @@
}
# endif
if (len) {
- (*block) (ctx->Yi.c, ctx->EKi.c, key);
+ sb_block128(ctx, block, ctx->Yi.c, ctx->EKi.c, key);
++ctr;
if (is_endian.little)
# ifdef BSWAP4
@@ -1311,7 +1367,7 @@
for (i = 0; i < len; ++i) {
u8 c;
if (n == 0) {
- (*block) (ctx->Yi.c, ctx->EKi.c, key);
+ sb_block128(ctx, block, ctx->Yi.c, ctx->EKi.c, key);
++ctr;
if (is_endian.little)
#ifdef BSWAP4
@@ -1392,7 +1448,7 @@
}
#if defined(GHASH) && !defined(OPENSSL_SMALL_FOOTPRINT)
while (len >= GHASH_CHUNK) {
- (*stream) (in, out, GHASH_CHUNK / 16, key, ctx->Yi.c);
+ sb_ctr128(ctx, stream, in, out, GHASH_CHUNK / 16, key, ctx->Yi.c);
ctr += GHASH_CHUNK / 16;
if (is_endian.little)
# ifdef BSWAP4
@@ -1411,7 +1467,7 @@
if ((i = (len & (size_t)-16))) {
size_t j = i / 16;
- (*stream) (in, out, j, key, ctx->Yi.c);
+ sb_ctr128(ctx, stream, in, out, j, key, ctx->Yi.c);
ctr += (unsigned int)j;
if (is_endian.little)
#ifdef BSWAP4
@@ -1436,7 +1492,7 @@
#endif
}
if (len) {
- (*ctx->block) (ctx->Yi.c, ctx->EKi.c, key);
+ sb_block128(ctx, ctx->block, ctx->Yi.c, ctx->EKi.c, key);
++ctr;
if (is_endian.little)
#ifdef BSWAP4
@@ -1517,7 +1573,7 @@
#if defined(GHASH) && !defined(OPENSSL_SMALL_FOOTPRINT)
while (len >= GHASH_CHUNK) {
GHASH(ctx, in, GHASH_CHUNK);
- (*stream) (in, out, GHASH_CHUNK / 16, key, ctx->Yi.c);
+ sb_ctr128(ctx, stream, in, out, GHASH_CHUNK / 16, key, ctx->Yi.c);
ctr += GHASH_CHUNK / 16;
if (is_endian.little)
# ifdef BSWAP4
@@ -1548,7 +1604,7 @@
j = i / 16;
in -= i;
#endif
- (*stream) (in, out, j, key, ctx->Yi.c);
+ sb_ctr128(ctx, stream, in, out, j, key, ctx->Yi.c);
ctr += (unsigned int)j;
if (is_endian.little)
#ifdef BSWAP4
@@ -1563,7 +1619,7 @@
len -= i;
}
if (len) {
- (*ctx->block) (ctx->Yi.c, ctx->EKi.c, key);
+ sb_block128(ctx, ctx->block, ctx->Yi.c, ctx->EKi.c, key);
++ctr;
if (is_endian.little)
#ifdef BSWAP4
diff --git a/src/third_party/openssl/openssl/crypto/modes/modes_lcl.h b/src/third_party/openssl/openssl/crypto/modes/modes_lcl.h
index 54febc9..db4bf70 100644
--- a/src/third_party/openssl/openssl/crypto/modes/modes_lcl.h
+++ b/src/third_party/openssl/openssl/crypto/modes/modes_lcl.h
@@ -122,10 +122,14 @@
void *key;
#if defined(OPENSSL_SYS_STARBOARD) && SB_API_VERSION >= 4
- // A handle to a HW-accelerated transformer for the GCM block cipher
- // mode. If valid, then this is used instead of any other state in the
- // context.
- SbCryptographyTransformer gcm_transformer;
+ // Whether in decrypt or encrypt mode.
+ int encrypt;
+
+ // The raw key specified to gcm_init.
+ char raw_key[512 / 8];
+
+ // The length of raw_key in bytes.
+ int raw_key_length;
// A handle to a HW-accelerated transformer for the CTR block cipher
// mode. If valid, then the software GCM code will wrap the hardware CTR
@@ -136,7 +140,12 @@
// mode. If valid, then the software GCM code will wrap the hardware ECB
// block cipher.
SbCryptographyTransformer ecb_transformer;
-#endif
+
+ // A handle to a HW-accelerated transformer for the GCM block cipher
+ // mode. If valid, then this is used instead of any other state in the
+ // context.
+ SbCryptographyTransformer gcm_transformer;
+#endif // defined(OPENSSL_SYS_STARBOARD) && SB_API_VERSION >= 4
};
struct xts128_context {
diff --git a/src/tools/gyp/pylib/gyp/MSVSVersion.py b/src/tools/gyp/pylib/gyp/MSVSVersion.py
index ad05788..6c44bb4 100644
--- a/src/tools/gyp/pylib/gyp/MSVSVersion.py
+++ b/src/tools/gyp/pylib/gyp/MSVSVersion.py
@@ -284,7 +284,8 @@
return path
-def _DetectVisualStudioVersions(versions_to_check, force_express):
+def _DetectVisualStudioVersions(versions_to_check, force_express,
+ vs_install_dir=None):
"""Collect the list of installed visual studio versions.
Returns:
@@ -306,7 +307,10 @@
for version in versions_to_check:
if version == '15.0':
# Version 15 does not include registry entries.
- path = r'C:\Program Files (x86)\Microsoft Visual Studio\2017\Professional\Common7\IDE'
+ if vs_install_dir:
+ path = os.path.join(vs_install_dir, r'Common7\IDE')
+ else:
+ path = r'C:\Program Files (x86)\Microsoft Visual Studio\2017\Professional\Common7\IDE'
path = _ConvertToCygpath(path)
full_path = os.path.join(path, 'devenv.exe')
if os.path.exists(full_path):
@@ -377,7 +381,9 @@
}
version = str(version)
- versions = _DetectVisualStudioVersions(version_map[version], 'e' in version)
+ vs_install_dir = os.environ.get('VS_INSTALL_DIR')
+ versions = _DetectVisualStudioVersions(version_map[version], 'e' in version,
+ vs_install_dir)
if not versions:
if version == 'auto':
# Default to 2005 if we couldn't find anything