| {# |
| # 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. |
| #} |
| {% from 'macros.cc.template' import add_extra_arguments %} |
| {% from 'macros.cc.template' import call_cobalt_function %} |
| {% from 'macros.cc.template' import check_if_object_implements_interface with context %} |
| {% from 'macros.cc.template' import constructor_implementation with context %} |
| {% from 'macros.cc.template' import function_implementation with context %} |
| {% from 'macros.cc.template' import get_impl_class_instance %} |
| {% from 'macros.cc.template' import nonstatic_function_prologue %} |
| {% from 'macros.cc.template' import overload_resolution_implementation with context %} |
| {% from 'macros.cc.template' import set_attribute_implementation with context %} |
| {% from 'macros.cc.template' import static_function_prologue %} |
| {% extends "interface-base.cc.template" %} |
| {% block includes %} |
| {{ super() }} |
| #include "{{generated_conversion_include}}" |
| |
| #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" |
| {% if is_exception_interface %} |
| #include "third_party/mozjs-45/js/src/jsexn.h" |
| {% endif %} |
| #include "third_party/mozjs-45/js/src/jsfriendapi.h" |
| {% endblock includes %} |
| {% block using_directives %} |
| {{ super() }} |
| 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; |
| {% endblock using_directives %} |
| {% block enumeration_declarations %} |
| {% if enumerations|length %} |
| // Declare and define these in the same namespace that the other overloads |
| // were brought into with the using declaration. |
| {% for enumeration in enumerations %} |
| void ToJSValue( |
| JSContext* context, |
| {{impl_class}}::{{enumeration.name}} in_enum, |
| JS::MutableHandleValue out_value); |
| void FromJSValue(JSContext* context, JS::HandleValue value, |
| int conversion_flags, ExceptionState* exception_state, |
| {{impl_class}}::{{enumeration.name}}* out_enum); |
| {% endfor %} |
| {% endif %} |
| {% endblock enumeration_declarations %} |
| {% block top_level_unnamed_namespace %} |
| {% if is_global_interface %} |
| JSObject* DummyFunctor( |
| JSContext* context, const scoped_refptr<Wrappable>& wrappable) { |
| NOTREACHED(); |
| return NULL; |
| } |
| {% endif %} |
| {% endblock top_level_unnamed_namespace %} |
| |
| {% 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) { |
| {{ get_impl_class_instance(impl_class) }} |
| return impl->CanQueryNamedProperty(property_name); |
| } |
| |
| void EnumerateSupportedNames(JSContext* context, JS::HandleObject object, |
| JS::AutoIdVector* properties) { |
| {{ get_impl_class_instance(impl_class) }} |
| MozjsPropertyEnumerator enumerator(context, properties); |
| impl->EnumerateNamedProperties(&enumerator); |
| } |
| |
| bool GetNamedProperty( |
| JSContext* context, JS::HandleObject object, JS::HandleId id, |
| JS::MutableHandleValue vp) { |
| JS::RootedValue id_value(context); |
| if (!JS_IdToValue(context, id, &id_value)) { |
| NOTREACHED(); |
| return false; |
| } |
| |
| {{ nonstatic_function_prologue(impl_class) }} |
| std::string property_name; |
| FromJSValue(context, id_value, kNoConversionFlags, &exception_state, |
| &property_name); |
| if (exception_state.is_exception_set()) { |
| // The ID should be an integer or a string, so we shouldn't have any |
| // exceptions converting to string. |
| NOTREACHED(); |
| return false; |
| } |
| {{ call_cobalt_function(impl_class, named_property_getter.type, |
| named_property_getter.name, ["property_name"], |
| named_property_getter.raises_exception, |
| named_property_getter.call_with) }} |
| if (!exception_state.is_exception_set()) { |
| vp.set(result_value); |
| } |
| return !exception_state.is_exception_set(); |
| } |
| |
| {% endif %} |
| {% if named_property_setter %} |
| bool SetNamedProperty( |
| JSContext* context, JS::HandleObject object, JS::HandleId id, |
| JS::MutableHandleValue vp, JS::ObjectOpResult& object_op_result) { |
| JS::RootedValue id_value(context); |
| if (!JS_IdToValue(context, id, &id_value)) { |
| NOTREACHED(); |
| return false; |
| } |
| {{ nonstatic_function_prologue(impl_class) }} |
| std::string property_name; |
| FromJSValue(context, id_value, kNoConversionFlags, &exception_state, |
| &property_name); |
| if (exception_state.is_exception_set()) { |
| // The ID should be an integer or a string, so we shouldn't have any |
| // exceptions converting to string. |
| NOTREACHED(); |
| return false; |
| } |
| TypeTraits<{{named_property_setter.type}} >::ConversionType value; |
| FromJSValue(context, vp, {{named_property_setter.conversion_flags}}, |
| &exception_state, &value); |
| if (exception_state.is_exception_set()) { |
| return false; |
| } |
| {{ call_cobalt_function(impl_class, "void", |
| named_property_setter.name, ["property_name", "value"], |
| named_property_setter.raises_exception, |
| named_property_setter.call_with) }} |
| |
| if (!exception_state.is_exception_set()) { |
| return object_op_result.succeed(); |
| } else { |
| return false; |
| } |
| } |
| |
| {% endif %} |
| {% if named_property_deleter %} |
| bool DeleteNamedProperty(JSContext* context, JS::HandleObject object, |
| const std::string& property_name) { |
| {{ nonstatic_function_prologue(impl_class) }} |
| {{ call_cobalt_function(impl_class, "void", |
| named_property_deleter.name, ["property_name"], |
| named_property_deleter.raises_exception, |
| named_property_deleter.call_with) }} |
| return !exception_state.is_exception_set(); |
| } |
| |
| {% endif %} |
| {% if indexed_property_getter %} |
| bool IsSupportedIndexProperty(JSContext* context, JS::HandleObject object, |
| uint32_t index) { |
| {{ get_impl_class_instance(impl_class) }} |
| return index < impl->length(); |
| } |
| |
| void EnumerateSupportedIndexes(JSContext* context, JS::HandleObject object, |
| JS::AutoIdVector* properties) { |
| {{ get_impl_class_instance(impl_class) }} |
| const uint32_t kNumIndexedProperties = impl->length(); |
| for (uint32_t i = 0; i < kNumIndexedProperties; ++i) { |
| properties->append(INT_TO_JSID(i)); |
| } |
| } |
| |
| bool GetIndexedProperty( |
| JSContext* context, JS::HandleObject object, JS::HandleId id, |
| JS::MutableHandleValue vp) { |
| JS::RootedValue id_value(context); |
| if (!JS_IdToValue(context, id, &id_value)) { |
| NOTREACHED(); |
| return false; |
| } |
| {{ nonstatic_function_prologue(impl_class) }} |
| uint32_t index; |
| FromJSValue(context, id_value, kNoConversionFlags, &exception_state, &index); |
| if (exception_state.is_exception_set()) { |
| // The ID should be an integer or a string, so we shouldn't have any |
| // exceptions converting to string. |
| NOTREACHED(); |
| return false; |
| } |
| {{ call_cobalt_function(impl_class, indexed_property_getter.type, |
| indexed_property_getter.name, ["index"], |
| indexed_property_getter.raises_exception, |
| indexed_property_getter.call_with) }} |
| if (!exception_state.is_exception_set()) { |
| vp.set(result_value); |
| } |
| return !exception_state.is_exception_set(); |
| } |
| |
| {% endif %} |
| {% if indexed_property_setter %} |
| bool SetIndexedProperty( |
| JSContext* context, JS::HandleObject object, JS::HandleId id, |
| JS::MutableHandleValue vp, JS::ObjectOpResult& object_op_result) { |
| JS::RootedValue id_value(context); |
| if (!JS_IdToValue(context, id, &id_value)) { |
| NOTREACHED(); |
| return false; |
| } |
| {{ nonstatic_function_prologue(impl_class) }} |
| uint32_t index; |
| FromJSValue(context, id_value, kNoConversionFlags, &exception_state, &index); |
| if (exception_state.is_exception_set()) { |
| // The ID should be an integer or a string, so we shouldn't have any |
| // exceptions converting to string. |
| NOTREACHED(); |
| return false; |
| } |
| TypeTraits<{{indexed_property_setter.type}} >::ConversionType value; |
| FromJSValue(context, vp, {{indexed_property_setter.conversion_flags}}, |
| &exception_state, &value); |
| if (exception_state.is_exception_set()) { |
| return false; |
| } |
| {{ call_cobalt_function(impl_class, "void", |
| indexed_property_setter.name, ["index", "value"], |
| indexed_property_setter.raises_exception, |
| indexed_property_setter.call_with) }} |
| if (!exception_state.is_exception_set()) { |
| return object_op_result.succeed(); |
| } else { |
| return false; |
| } |
| } |
| |
| {% endif %} |
| {% if indexed_property_deleter %} |
| bool DeleteIndexedProperty( |
| JSContext* context, JS::HandleObject object, uint32_t index) { |
| {{ nonstatic_function_prologue(impl_class) }} |
| {{ call_cobalt_function(impl_class, "void", |
| indexed_property_deleter.name, ["index"], |
| indexed_property_deleter.raises_exception, |
| indexed_property_deleter.call_with) }} |
| return !exception_state.is_exception_set(); |
| } |
| |
| {% endif %} |
| class {{binding_class}}Handler : public ProxyHandler { |
| public: |
| {{binding_class}}Handler() |
| : ProxyHandler(indexed_property_hooks, named_property_hooks) {} |
| |
| private: |
| static NamedPropertyHooks named_property_hooks; |
| static IndexedPropertyHooks indexed_property_hooks; |
| }; |
| |
| ProxyHandler::NamedPropertyHooks |
| {{binding_class}}Handler::named_property_hooks = { |
| {{ "IsSupportedNamedProperty" if named_property_getter else "NULL" }}, |
| {{ "EnumerateSupportedNames" if named_property_getter else "NULL" }}, |
| {{ "GetNamedProperty" if named_property_getter else "NULL" }}, |
| {{ "SetNamedProperty" if named_property_setter else "NULL" }}, |
| {{ "DeleteNamedProperty" if named_property_deleter else "NULL" }}, |
| }; |
| ProxyHandler::IndexedPropertyHooks |
| {{binding_class}}Handler::indexed_property_hooks = { |
| {{ "IsSupportedIndexProperty" if indexed_property_getter else "NULL" }}, |
| {{ "EnumerateSupportedIndexes" if indexed_property_getter else "NULL" }}, |
| {{ "GetIndexedProperty" if indexed_property_getter else "NULL" }}, |
| {{ "SetIndexedProperty" if indexed_property_setter else "NULL" }}, |
| {{ "DeleteIndexedProperty" if indexed_property_deleter else "NULL" }}, |
| }; |
| |
| static base::LazyInstance<{{binding_class}}Handler> |
| proxy_handler; |
| |
| {% if constructor %} |
| bool Constructor(JSContext* context, unsigned int argc, JS::Value* vp); |
| {% endif %} |
| {% for constant in constants %} |
| bool get_{{constant.idl_name}}( |
| JSContext* context, unsigned argc, JS::Value* vp) { |
| {% if constant.can_use_compile_assert %} |
| COMPILE_ASSERT({{impl_class}}::{{constant.name}} == {{constant.value}}, |
| ValueFor{{impl_class}}_{{constant.name}}DoesNotMatchIDL); |
| {% else %} |
| DCHECK_EQ({{constant.value}}, {{impl_class}}::{{constant.name}}) << |
| "The value for {{impl_class}}::{{constant.name}} does not match " |
| "the value in the interface definition."; |
| {% endif %} |
| JS::CallArgs args = JS::CallArgsFromVp(argc, vp); |
| JS::RootedObject object(context, &args.thisv().toObject()); |
| MozjsExceptionState exception_state(context); |
| JS::RootedValue result_value(context); |
| ToJSValue(context, {{constant.value}}, &result_value); |
| if (!exception_state.is_exception_set()) { |
| args.rval().set(result_value); |
| } |
| return !exception_state.is_exception_set(); |
| } |
| |
| {% endfor %} |
| 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, {{binding_class}}::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 = { |
| "{{interface_name}}", |
| {{ "JSCLASS_GLOBAL_FLAGS" if is_global_interface else 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 |
| {{ "JS_GlobalObjectTraceHook" if is_global_interface else "&WrapperPrivate::Trace" }}, // trace |
| }; |
| |
| const JSClass prototype_class_definition = { |
| "{{interface_name}}Prototype", |
| }; |
| |
| const JSClass interface_object_class_definition = { |
| "{{interface_name}}Constructor", |
| 0, |
| NULL, // addProperty |
| NULL, // delProperty |
| NULL, // getProperty |
| NULL, // setProperty |
| NULL, // enumerate |
| NULL, // resolve |
| NULL, // mayResolve |
| NULL, // finalize |
| NULL, // call |
| &HasInstance, |
| {% if constructor %} |
| Constructor, |
| {% else %} |
| NULL, |
| {% endif %} |
| }; |
| |
| {% for attribute in attributes + static_attributes %} |
| {% if attribute.conditional %} |
| #if defined({{attribute.conditional}}) |
| {% endif %} |
| {% if attribute.is_constructor_attribute %} |
| bool get_{{attribute.idl_name}}( |
| JSContext* context, unsigned argc, JS::Value* vp) { |
| |
| JS::CallArgs args = JS::CallArgsFromVp(argc, vp); |
| JS::RootedObject object(context, &args.thisv().toObject()); |
| JS::RootedObject global_object( |
| context, JS_GetGlobalForObject(context, object)); |
| DCHECK(global_object); |
| JS::RootedObject interface_object(context, |
| Mozjs{{attribute.interface_name}}::GetInterfaceObject( |
| context, global_object)); |
| args.rval().setObject(*interface_object); |
| return true; |
| } |
| {% else %} |
| {% if attribute.is_static %} |
| bool staticget_{{attribute.idl_name}}( |
| JSContext* context, unsigned argc, JS::Value* vp) { |
| {{ static_function_prologue() -}} |
| {% else %} |
| bool get_{{attribute.idl_name}}( |
| JSContext* context, unsigned argc, JS::Value* vp) { |
| {% endif %} |
| JS::CallArgs args = JS::CallArgsFromVp(argc, vp); |
| JS::RootedObject object(context, &args.thisv().toObject()); |
| {% if not attribute.is_static %} |
| {{ check_if_object_implements_interface() }} |
| {{ nonstatic_function_prologue(impl_class) }} |
| {% endif %} |
| {{ call_cobalt_function(impl_class, attribute.type, |
| attribute.getter_function_name, [], |
| attribute.raises_exception, attribute.call_with, |
| attribute.is_static) }} |
| if (!exception_state.is_exception_set()) { |
| args.rval().set(result_value); |
| } |
| return !exception_state.is_exception_set(); |
| } |
| |
| {% if attribute.has_setter %} |
| {% if attribute.is_static %} |
| bool staticset_{{attribute.idl_name}}( |
| JSContext* context, unsigned argc, JS::Value* vp) { |
| {% else %} |
| bool set_{{attribute.idl_name}}( |
| JSContext* context, unsigned argc, JS::Value* vp) { |
| {% endif %} |
| |
| JS::CallArgs args = JS::CallArgsFromVp(argc, vp); |
| JS::RootedObject object(context, &args.thisv().toObject()); |
| |
| {% if attribute.is_static %} |
| {{ static_function_prologue() }} |
| {% else %} |
| {{ check_if_object_implements_interface() }} |
| {{ nonstatic_function_prologue(impl_class)}} |
| {% endif %} {#- attribute.is_static #} |
| {{ set_attribute_implementation(attribute, impl_class) -}} |
| } |
| {% endif %} {#- attribute.has_setter #} |
| |
| {% endif %} |
| {% if attribute.conditional %} |
| #endif // {{attribute.conditional}} |
| {% endif %} {#- attribute.is_constructor_attribute #} |
| {% endfor %} |
| {%- for operation in operations + static_operations %} |
| {% if operation.conditional %} |
| #if defined({{operation.conditional}}) |
| {% endif %} |
| {% set boundFunctionPrefix = "staticfcn_" if operation.is_static else "fcn_" %} |
| {% for overload in operation.overloads if operation.overloads|length > 1 %} |
| bool {{boundFunctionPrefix}}{{operation.idl_name}}{{overload.overload_index}}( |
| JSContext* context, uint32_t argc, JS::Value *vp) { |
| {{ function_implementation(overload) -}} |
| } |
| |
| {% endfor %} |
| bool {{boundFunctionPrefix}}{{operation.idl_name}}( |
| JSContext* context, uint32_t argc, JS::Value *vp) { |
| {% if operation.overloads|length == 1 %} |
| {{ function_implementation(operation.overloads[0]) -}} |
| {% else %} |
| {{ overload_resolution_implementation( |
| operation, boundFunctionPrefix + operation.idl_name) }} |
| {% endif %} |
| } |
| |
| {% if operation.conditional %} |
| #endif // {{operation.conditional}} |
| {% endif %} |
| {% endfor %} |
| |
| {% if stringifier %} |
| bool Stringifier(JSContext* context, unsigned argc, JS::Value *vp) { |
| MozjsExceptionState exception_state(context); |
| // Compute the 'this' value. |
| JS::RootedValue this_value(context, JS_ComputeThis(context, vp)); |
| // 'this' should be an object. |
| JS::RootedObject object(context); |
| |
| if (JS_TypeOfValue(context, this_value) != JSTYPE_OBJECT) { |
| NOTREACHED(); |
| return false; |
| } |
| if (!JS_ValueToObject(context, this_value, &object)) { |
| NOTREACHED(); |
| return false; |
| } |
| WrapperPrivate* wrapper_private = |
| WrapperPrivate::GetFromObject(context, object); |
| {{impl_class}}* impl = |
| wrapper_private->wrappable<{{impl_class}}>().get(); |
| if (!impl) { |
| exception_state.SetSimpleException(cobalt::script::kStringifierProblem); |
| NOTREACHED(); |
| return false; |
| } |
| std::string stringified = impl->{{stringifier.name}}(); |
| JS::CallArgs args = JS::CallArgsFromVp(argc, vp); |
| JS::RootedString rooted_string(context, |
| JS_NewStringCopyN(context, stringified.c_str(), stringified.length())); |
| args.rval().set(JS::StringValue(rooted_string)); |
| return true; |
| } |
| |
| {% endif %} |
| |
| const JSPropertySpec prototype_properties[] = { |
| {% for constant in constants %} |
| { |
| "{{constant.idl_name}}", |
| JSPROP_PERMANENT | JSPROP_SHARED | JSPROP_ENUMERATE, |
| { { &get_{{constant.idl_name}}, NULL } }, |
| JSNATIVE_WRAPPER(NULL) |
| }, |
| {% endfor %} |
| {% for attribute in attributes if not attribute.is_constructor_attribute %} |
| {% if attribute.conditional %} |
| #if defined({{attribute.conditional}}) |
| {% endif %} |
| {% if attribute.has_setter %} |
| { // Read/Write property |
| "{{attribute.idl_name}}", |
| JSPROP_SHARED | JSPROP_ENUMERATE, |
| { { &get_{{attribute.idl_name}}, NULL } }, |
| { { &set_{{attribute.idl_name}}, NULL } }, |
| }, |
| {% else %} |
| { // Readonly attribute |
| "{{attribute.idl_name}}", |
| JSPROP_SHARED | JSPROP_ENUMERATE, |
| { { &get_{{attribute.idl_name}}, NULL } }, |
| JSNATIVE_WRAPPER(NULL), |
| }, |
| {% endif %} |
| {% if attribute.conditional %} |
| #endif // {{attribute.conditional}} |
| {% endif %} |
| {% endfor %} |
| JS_PS_END |
| }; |
| |
| const JSFunctionSpec prototype_functions[] = { |
| {% if stringifier %} |
| JS_FNSPEC("toString", Stringifier, NULL, 0, JSPROP_ENUMERATE, NULL), |
| {% endif %} |
| {% for operation in operations %} |
| {% if operation.conditional %} |
| |
| #if defined({{operation.conditional}}) |
| |
| {% endif %} |
| JS_FNSPEC( |
| "{{ operation.idl_name }}", fcn_{{operation.idl_name}}, NULL, |
| {{ operation.length }}, JSPROP_ENUMERATE, NULL), |
| {% if operation.conditional %} |
| #endif // {{operation.conditional}} |
| {% endif %} |
| {% endfor %} |
| JS_FS_END |
| }; |
| |
| const JSPropertySpec interface_object_properties[] = { |
| {% for constant in constants %} |
| { |
| "{{constant.idl_name}}", |
| JSPROP_SHARED | JSPROP_ENUMERATE, |
| { { &get_{{constant.idl_name}}, NULL } }, |
| JSNATIVE_WRAPPER(NULL), |
| }, |
| |
| {% endfor %} |
| {% for attribute in static_attributes %} |
| {% if attribute.conditional %} |
| #if defined({{attribute.conditional}}) |
| {% endif %} |
| {% if attribute.has_setter %} |
| { // Static read/write attribute. |
| "{{attribute.idl_name}}", |
| JSPROP_SHARED | JSPROP_ENUMERATE, |
| { { &staticget_{{attribute.idl_name}}, NULL } }, |
| { { &staticset_{{attribute.idl_name}}, NULL } }, |
| }, |
| {% else %} |
| { // Static readonly attribute. |
| "{{attribute.idl_name}}", |
| JSPROP_SHARED | JSPROP_ENUMERATE, |
| { { &staticget_{{attribute.idl_name}} } }, |
| JSNATIVE_WRAPPER(NULL), |
| }, |
| {% endif %} |
| {% if attribute.conditional %} |
| #endif // {{attribute.conditional}} |
| {% endif %} |
| {% endfor %} |
| JS_PS_END |
| }; |
| |
| const JSFunctionSpec interface_object_functions[] = { |
| {% for operation in static_operations %} |
| {% if operation.conditional %} |
| #if defined({{operation.conditional}}) |
| {% endif %} |
| JS_FNSPEC( |
| "{{ operation.idl_name }}", staticfcn_{{operation.idl_name}}, NULL, |
| {{ operation.length }}, JSPROP_ENUMERATE, NULL), |
| {% if operation.conditional %} |
| #endif // {{operation.conditional}} |
| {% endif %} |
| {% endfor %} |
| JS_FS_END |
| }; |
| |
| const JSPropertySpec own_properties[] = { |
| {% for attribute in attributes if attribute.is_constructor_attribute %} |
| {% if attribute.conditional %} |
| #if defined({{attribute.conditional}}) |
| {% endif %} |
| { // Constructor attribute |
| "{{attribute.idl_name}}", |
| JSPROP_SHARED | JSPROP_ENUMERATE, |
| { { &get_{{attribute.idl_name}}, NULL } }, |
| JSNATIVE_WRAPPER(NULL), |
| }, |
| {% if attribute.conditional %} |
| #endif // {{attribute.conditional}} |
| {% endif %} |
| {% endfor %} |
| 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)); |
| |
| {% if parent_interface %} |
| JS::RootedObject parent_prototype( |
| context, {{parent_interface}}::GetPrototype(context, global_object)); |
| {% elif is_exception_interface %} |
| // Get Error prototype. |
| JS::RootedObject parent_prototype(context); |
| bool success_check = JS_GetClassPrototype( |
| context, js::GetExceptionProtoKey(JSEXN_ERR), &parent_prototype); |
| DCHECK(success_check); |
| {% else %} |
| JS::RootedObject parent_prototype( |
| context, JS_GetObjectPrototype(context, global_object)); |
| {% endif %} |
| 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); |
| |
| {% if has_interface_object %} |
| 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[] = |
| "{{ named_constructor if named_constructor else interface.name }}"; |
| name_value.setString(JS_NewStringCopyZ(context, name)); |
| success = JS_DefineProperty( |
| context, rooted_interface_object, "name", name_value, JSPROP_READONLY, |
| NULL, NULL); |
| DCHECK(success); |
| {% if constructor %} |
| |
| // 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({{constructor.length}}); |
| success = JS_DefineProperty( |
| context, rooted_interface_object, "length", length_value, |
| JSPROP_READONLY, NULL, NULL); |
| DCHECK(success); |
| {% endif %} |
| |
| // 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); |
| {% endif %} |
| } |
| |
| 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 |
| |
| {% if is_global_interface %} |
| JSObject* {{binding_class}}::CreateProxy( |
| JSContext* context, const scoped_refptr<Wrappable>& wrappable) { |
| |
| InterfaceData* interface_data = GetInterfaceData(context); |
| |
| JS::RootedObject global_object( |
| context, JS_NewGlobalObject(context, |
| &instance_class_definition, NULL, |
| JS::FireOnNewGlobalHook, |
| JS::CompartmentOptions().setTrace(WrapperPrivate::Trace))); |
| DCHECK(global_object); |
| |
| // Initialize standard JS constructors prototypes and top-level functions such |
| // as Object, isNan, etc. |
| JSAutoCompartment auto_compartment(context, global_object); |
| bool success = JS_InitStandardClasses(context, global_object); |
| DCHECK(success); |
| |
| JS::RootedObject prototype( |
| context, {{binding_class}}::GetPrototype(context, global_object)); |
| DCHECK(prototype); |
| JS_SetPrototype(context, global_object, prototype); |
| |
| JS_SetImmutablePrototype(context, global_object, &success); |
| DCHECK(success); |
| |
| // Add own properties. |
| success = JS_DefineProperties(context, global_object, own_properties); |
| DCHECK(success); |
| |
| JS::RootedObject proxy(context, |
| ProxyHandler::NewProxy( |
| context, proxy_handler.Pointer(), global_object, prototype)); |
| WrapperPrivate::AddPrivateData(context, proxy, wrappable); |
| |
| // Set the global object proxy pointer, so we can access the standard classes |
| // such as the base Object prototype when looking up our prototype. |
| MozjsGlobalEnvironment* global_environment = |
| static_cast<MozjsGlobalEnvironment*>(JS_GetContextPrivate(context)); |
| global_environment->SetGlobalObjectProxyAndWrapper(proxy, wrappable); |
| return proxy; |
| } |
| {% else %} |
| // static |
| JSObject* {{binding_class}}::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)); |
| {% 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; |
| } |
| |
| {% endif %} |
| // static |
| const JSClass* {{binding_class}}::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* {{binding_class}}::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; |
| } |
| |
| {% if has_interface_object %} |
| // static |
| JSObject* {{binding_class}}::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; |
| } |
| |
| {% endif %} {#- has_interface_object #} |
| |
| namespace { |
| {% if constructor %} |
| {% for overload in constructor.overloads if constructor.overloads|length > 1 %} |
| bool Constructor{{overload.overload_index}}( |
| JSContext* context, unsigned int argc, JS::Value* vp) { |
| {{ constructor_implementation(overload) -}} |
| } |
| |
| {% endfor %} |
| bool Constructor(JSContext* context, unsigned int argc, JS::Value* vp) { |
| {% if constructor.overloads|length == 1 %} |
| {{ constructor_implementation(constructor.overloads[0]) -}} |
| {% else %} |
| {{ overload_resolution_implementation(constructor, "Constructor")}} |
| {% endif %} |
| } |
| {% endif %} |
| } // namespace |
| |
| {% endblock implementation %} |
| {% block create_global_object_impl %} |
| MozjsGlobalEnvironment* mozjs_global_environment = |
| base::polymorphic_downcast<MozjsGlobalEnvironment*>(this); |
| JSContext* context = mozjs_global_environment->context(); |
| |
| JSAutoRequest auto_request(context); |
| {{binding_class}}::CreateProxy( |
| context, global_interface); |
| mozjs_global_environment->SetEnvironmentSettings(environment_settings); |
| mozjs_global_environment->EvaluateAutomatics(); |
| |
| WrapperFactory* wrapper_factory = |
| mozjs_global_environment->wrapper_factory(); |
| {% for interface in all_interfaces %} |
| {% if interface.conditional %} |
| #if defined({{interface.conditional}}) |
| {% endif %} |
| {# Pass in a dummy CreateProxy for global interface #} |
| {% if interface.name == impl_class %} |
| wrapper_factory->RegisterWrappableType( |
| {{interface.name}}::{{interface.name}}WrappableType(), |
| base::Bind(DummyFunctor), |
| base::Bind(Mozjs{{interface.name}}::PrototypeClass)); |
| {% else %} |
| wrapper_factory->RegisterWrappableType( |
| {{interface.name}}::{{interface.name}}WrappableType(), |
| base::Bind(Mozjs{{interface.name}}::CreateProxy), |
| base::Bind(Mozjs{{interface.name}}::PrototypeClass)); |
| {% endif %} |
| {% if interface.conditional %} |
| #endif // defined({{interface.conditional}}) |
| {% endif %} |
| {% endfor %} |
| |
| {% endblock create_global_object_impl %} |
| |
| {% block enumeration_definitions %} |
| {% for enumeration in enumerations %} |
| |
| inline void ToJSValue( |
| JSContext* context, |
| {{impl_class}}::{{enumeration.name}} in_enum, |
| JS::MutableHandleValue out_value) { |
| |
| switch (in_enum) { |
| {% for value, idl_value in enumeration.value_pairs %} |
| case {{impl_class}}::{{value}}: |
| ToJSValue(context, std::string("{{idl_value}}"), out_value); |
| return; |
| {% endfor %} |
| default: |
| NOTREACHED(); |
| out_value.set(JS::UndefinedValue()); |
| } |
| } |
| |
| inline void FromJSValue(JSContext* context, JS::HandleValue value, |
| int conversion_flags, ExceptionState* exception_state, |
| {{impl_class}}::{{enumeration.name}}* out_enum) { |
| DCHECK_EQ(0, conversion_flags) << "Unexpected conversion flags."; |
| // JSValue -> IDL enum algorithm described here: |
| // http://heycam.github.io/webidl/#es-enumeration |
| // 1. Let S be the result of calling ToString(V). |
| JS::RootedString rooted_string(context, JS::ToString(context, value)); |
| |
| bool match = false; |
| // 3. Return the enumeration value of type E that is equal to S. |
| {% for value, idl_value in enumeration.value_pairs %} |
| {{-" else " if not loop.first}}if (JS_StringEqualsAscii( |
| context, rooted_string, "{{idl_value}}", &match) |
| && match) { |
| *out_enum = {{impl_class}}::{{value}}; |
| }{% endfor %} else { |
| // 2. If S is not one of E's enumeration values, then throw a TypeError. |
| exception_state->SetSimpleException(cobalt::script::kConvertToEnumFailed); |
| return; |
| } |
| } |
| {% endfor %} |
| {% endblock enumeration_definitions %} |