Make it possible to inherit from any constructable host object

This CL makes it possible for authors to extend any host object (e.g., DOM
objects) and to use those objects in all the usual places they can be used in
the API.

R=esprehn@chromium.org

Review URL: https://codereview.chromium.org/936193005
This commit is contained in:
Adam Barth 2015-02-19 23:09:51 -08:00
parent 74290d5007
commit f562073fe2
7 changed files with 74 additions and 10 deletions

View File

@ -106,7 +106,7 @@ def argument_context(interface, method, argument, index):
idl_type = argument.idl_type
this_cpp_value = cpp_value(interface, method, index)
auto_scope = not 'DartNoAutoScope' in extended_attributes
arg_index = index + 1 if not (method.is_static or method.is_constructor) else index
arg_index = index + 1 if not method.is_static else index
preprocessed_type = str(idl_type.preprocessed_type)
local_cpp_type = idl_type.cpp_type_args(argument.extended_attributes, raw_type=True)
default_value = argument.default_cpp_value

View File

@ -19,16 +19,17 @@ part of sky.core;
{%- endfor -%}
{%- endmacro -%}
abstract class {{interface_name}} extends {{ parent_interface if parent_interface else 'NativeFieldWrapperClass2' }} {
{% if not constructors %}abstract {% endif -%}
class {{interface_name}} extends {{ parent_interface if parent_interface else 'NativeFieldWrapperClass2' }} {
// Constructors
{# TODO(eseidel): We only ever have one constructor. #}
{%- for constructor in constructors -%}
static {{interface_name}} _constructor({{ args_macro(constructor.arguments) }}) native "{{interface_name}}_constructorCallback";
factory {{interface_name}}({{ args_macro(constructor.arguments) }}) => _constructor(
{%- for constructor in constructors %}
void _constructor({{ args_macro(constructor.arguments) }}) native "{{interface_name}}_constructorCallback";
{{interface_name}}({{ args_macro(constructor.arguments) }}) { _constructor(
{%- for arg in constructor.arguments -%}
{{ arg.name }}{% if not loop.last %}, {% endif %}
{%- endfor -%}
);
); }
{% endfor %}
// Attributes

View File

@ -335,7 +335,7 @@ static void {{static_method_name(constructor.name, overload_index)}}(Dart_Native
ExceptionState es;
{% endif %}
{{generate_arguments(constructor) | indent(8)}}
{{callback_return(constructor, constructor.dart_set_return_value, constructor.cpp_value) | indent(8)}}
{{constructor.cpp_value}}->AssociateWithDartWrapper(args);
{% if constructor.has_exception_state %}
if (es.had_exception()) {
exception = es.GetDartException(args, {{constructor.auto_scope}});
@ -368,6 +368,8 @@ static void eventConstructorCallback(Dart_NativeArguments args)
{% macro generate_resolver_constructor(dart_class, class_name, constructor) %}
{% for native_entry in constructor.native_entries %}
{% set resolver_string = native_entry.resolver_string %}
{% set args_one_based = constructor.number_of_arguments + 1 %}
{% set args_required_one_based = constructor.number_of_required_arguments + 1 %}
{% if constructor.overload_index %}
{% set constructor_name = static_method_name(constructor.name) + "Dispatcher" %}
{% else %}
@ -376,9 +378,9 @@ static void eventConstructorCallback(Dart_NativeArguments args)
{% if has_custom_constructor %}
if (name == "{{resolver_string}}") {
{% elif constructor.number_of_arguments == constructor.number_of_required_arguments %}
if (argumentCount == {{constructor.number_of_arguments}} && name == "{{resolver_string}}") {
if (argumentCount == {{args_one_based}} && name == "{{resolver_string}}") {
{% else %}
if (argumentCount >= {{constructor.number_of_required_arguments}} && argumentCount <= {{constructor.number_of_arguments}} && name == "{{resolver_string}}") {
if (argumentCount >= {{args_required_one_based}} && argumentCount <= {{args_one_based}} && name == "{{resolver_string}}") {
{% endif %}
*autoSetupScope = {{constructor.auto_scope}};
return {{dart_class}}Internal::{{constructor_name}};

View File

@ -41,6 +41,29 @@ Dart_Handle DartWrappable::CreateDartWrapper(DartState* dart_state) {
return wrapper;
}
void DartWrappable::AssociateWithDartWrapper(Dart_NativeArguments args) {
DCHECK(!dart_wrapper_);
Dart_Handle wrapper = Dart_GetNativeArgument(args, 0);
CHECK(!LogIfError(wrapper));
intptr_t native_fields[kNumberOfNativeFields];
CHECK(!LogIfError(Dart_GetNativeFieldsOfArgument(
args, 0, kNumberOfNativeFields, native_fields)));
CHECK(!native_fields[kPeerIndex]);
CHECK(!native_fields[kWrapperInfoIndex]);
const DartWrapperInfo& info = GetDartWrapperInfo();
CHECK(!LogIfError(Dart_SetNativeInstanceField(
wrapper, kPeerIndex, reinterpret_cast<intptr_t>(this))));
CHECK(!LogIfError(Dart_SetNativeInstanceField(
wrapper, kWrapperInfoIndex, reinterpret_cast<intptr_t>(&info))));
info.ref_object(this); // Balanced in FinalizeDartWrapper.
dart_wrapper_ = Dart_NewPrologueWeakPersistentHandle(
wrapper, this, info.size_in_bytes, &FinalizeDartWrapper);
}
void DartWrappable::FinalizeDartWrapper(void* isolate_callback_data,
Dart_WeakPersistentHandle wrapper,
void* peer) {

View File

@ -40,6 +40,7 @@ class DartWrappable {
virtual void AcceptDartGCVisitor(DartGCVisitor& visitor) const;
Dart_Handle CreateDartWrapper(DartState* dart_state);
void AssociateWithDartWrapper(Dart_NativeArguments args);
Dart_WeakPersistentHandle dart_wrapper() const { return dart_wrapper_; }
protected:
@ -133,7 +134,7 @@ struct DartConverter<RefPtr<T>> {
};
template<typename T>
static T* GetReceiver(Dart_NativeArguments args) {
inline T* GetReceiver(Dart_NativeArguments args) {
intptr_t receiver;
Dart_Handle result = Dart_GetNativeReceiver(args, &receiver);
DCHECK(!Dart_IsError(result));

View File

@ -0,0 +1,6 @@
CONSOLE: unittest-suite-wait-for-done
CONSOLE: PASS: should be able to insert in DOM
CONSOLE:
CONSOLE: All 1 tests passed.
CONSOLE: unittest-suite-success
DONE

View File

@ -0,0 +1,31 @@
<sky>
<script>
import "../resources/third_party/unittest/unittest.dart";
import "../resources/unit.dart";
import "dart:sky";
class CustomText extends Text {
CustomText() : super("awesome");
bool get isCustom => true;
}
void main() {
initUnit();
test("should be able to insert in DOM", () {
var child = new CustomText();
expect(child.isCustom, isTrue);
expect(child.parentNode, isNull);
expect(child.data, equals("awesome"));
var parent = document.createElement("div");
parent.appendChild(child);
expect(child.parentNode, equals(parent));
expect(parent.firstChild, equals(child));
expect(parent.firstChild.isCustom, isTrue);
});
}
</script>
</sky>