Home | History | Annotate | Download | only in templates
      1 {##############################################################################}
      2 {% macro generate_method(method, world_suffix) %}
      3 {% filter conditional(method.conditional_string) %}
      4 static void {{method.name}}{{method.overload_index}}Method{{world_suffix}}(const v8::FunctionCallbackInfo<v8::Value>& info)
      5 {
      6     {% if method.is_raises_exception or method.is_check_security_for_frame or
      7           method.name in ['addEventListener', 'removeEventListener'] %}
      8     ExceptionState exceptionState(ExceptionState::ExecutionContext, "{{method.name}}", "{{interface_name}}", info.Holder(), info.GetIsolate());
      9     {% endif %}
     10     {% if method.name in ['addEventListener', 'removeEventListener'] %}
     11     {{add_remove_event_listener_method(method.name) | indent}}
     12     {% else %}
     13     {% if method.number_of_required_arguments %}
     14     if (UNLIKELY(info.Length() < {{method.number_of_required_arguments}})) {
     15         {{throw_type_error(method,
     16               'ExceptionMessages::notEnoughArguments(%s, info.Length())' %
     17                   method.number_of_required_arguments)}}
     18         return;
     19     }
     20     {% endif %}
     21     {% if not method.is_static %}
     22     {{cpp_class}}* imp = {{v8_class}}::toNative(info.Holder());
     23     {% endif %}
     24     {% if method.is_custom_element_callbacks %}
     25     CustomElementCallbackDispatcher::CallbackDeliveryScope deliveryScope;
     26     {% endif %}
     27     {% if method.is_check_security_for_frame %}
     28     if (!BindingSecurity::shouldAllowAccessToFrame(imp->frame(), exceptionState)) {
     29         exceptionState.throwIfNeeded();
     30         return;
     31     }
     32     {% endif %}
     33     {% if method.is_check_security_for_node %}
     34     if (!BindingSecurity::shouldAllowAccessToNode(imp->{{method.name}}(exceptionState), exceptionState)) {
     35         v8SetReturnValueNull(info);
     36         exceptionState.throwIfNeeded();
     37         return;
     38     }
     39     {% endif %}
     40     {% for argument in method.arguments %}
     41     {{generate_argument(method, argument) | indent}}
     42     {% endfor %}
     43     {{cpp_method_call(method, method.v8_set_return_value, method.cpp_value) | indent}}
     44     {% endif %}{# addEventListener, removeEventListener #}
     45 }
     46 {% endfilter %}
     47 {% endmacro %}
     48 
     49 
     50 {######################################}
     51 {% macro add_remove_event_listener_method(method_name) %}
     52 {# Set template values for addEventListener vs. removeEventListener #}
     53 {% set listener_lookup_type, listener, hidden_dependency_action =
     54     ('ListenerFindOrCreate', 'listener', 'createHiddenDependency')
     55     if method_name == 'addEventListener' else
     56     ('ListenerFindOnly', 'listener.get()', 'removeHiddenDependency')
     57 %}
     58 EventTarget* impl = {{v8_class}}::toNative(info.Holder());
     59 if (DOMWindow* window = impl->toDOMWindow()) {
     60     if (!BindingSecurity::shouldAllowAccessToFrame(window->frame(), exceptionState)) {
     61         exceptionState.throwIfNeeded();
     62         return;
     63     }
     64     if (!window->document())
     65         return;
     66 }
     67 RefPtr<EventListener> listener = V8EventListenerList::getEventListener(info[1], false, {{listener_lookup_type}});
     68 if (listener) {
     69     V8TRYCATCH_FOR_V8STRINGRESOURCE_VOID(V8StringResource<WithNullCheck>, eventName, info[0]);
     70     impl->{{method_name}}(eventName, {{listener}}, info[2]->BooleanValue());
     71     if (!impl->toNode())
     72         {{hidden_dependency_action}}(info.Holder(), info[1], {{v8_class}}::eventListenerCacheIndex, info.GetIsolate());
     73 }
     74 {% endmacro %}
     75 
     76 
     77 {######################################}
     78 {% macro generate_argument(method, argument) %}
     79 {% if argument.is_optional and not argument.has_default and
     80       argument.idl_type != 'Dictionary' %}
     81 {# Optional arguments without a default value generate an early call with
     82    fewer arguments if they are omitted.
     83    Optional Dictionary arguments default to empty dictionary. #}
     84 if (UNLIKELY(info.Length() <= {{argument.index}})) {
     85     {{cpp_method_call(method, argument.v8_set_return_value, argument.cpp_value) | indent}}
     86     return;
     87 }
     88 {% endif %}
     89 {% if method.is_strict_type_checking and argument.is_wrapper_type %}
     90 {# Type checking for wrapper interface types (if interface not implemented,
     91    throw TypeError), per http://www.w3.org/TR/WebIDL/#es-interface #}
     92 if (info.Length() > {{argument.index}} && !isUndefinedOrNull(info[{{argument.index}}]) && !V8{{argument.idl_type}}::hasInstance(info[{{argument.index}}], info.GetIsolate(), worldType(info.GetIsolate()))) {
     93     {{throw_type_error(method, '"parameter %s is not of type \'%s\'."' %
     94                                (argument.index + 1, argument.idl_type))}}
     95     return;
     96 }
     97 {% endif %}
     98 {% if argument.is_clamp %}
     99 {# NaN is treated as 0: http://www.w3.org/TR/WebIDL/#es-type-mapping #}
    100 {{argument.cpp_type}} {{argument.name}} = 0;
    101 V8TRYCATCH_VOID(double, {{argument.name}}NativeValue, info[{{argument.index}}]->NumberValue());
    102 if (!std::isnan({{argument.name}}NativeValue))
    103     {# IDL type is used for clamping, for the right bounds, since different
    104        IDL integer types have same internal C++ type (int or unsigned) #}
    105     {{argument.name}} = clampTo<{{argument.idl_type}}>({{argument.name}}NativeValue);
    106 {% elif argument.idl_type == 'SerializedScriptValue' %}
    107 {% set did_throw = argument.name + 'DidThrow' %}
    108 bool {{did_throw}} = false;
    109 {{argument.cpp_type}} {{argument.name}} = SerializedScriptValue::create(info[{{argument.index}}], 0, 0, {{did_throw}}, info.GetIsolate());
    110 if ({{did_throw}})
    111     return;
    112 {% elif argument.is_variadic_wrapper_type %}
    113 Vector<{{argument.cpp_type}} > {{argument.name}};
    114 for (int i = {{argument.index}}; i < info.Length(); ++i) {
    115     if (!V8{{argument.idl_type}}::hasInstance(info[i], info.GetIsolate(), worldType(info.GetIsolate()))) {
    116         {{throw_type_error(method, '"parameter %s is not of type \'%s\'."' %
    117                                    (argument.index + 1, argument.idl_type))}}
    118         return;
    119     }
    120     {{argument.name}}.append(V8{{argument.idl_type}}::toNative(v8::Handle<v8::Object>::Cast(info[i])));
    121 }
    122 {% else %}
    123 {{argument.v8_value_to_local_cpp_value}};
    124 {% endif %}
    125 {% if argument.enum_validation_expression %}
    126 {# Methods throw on invalid enum values: http://www.w3.org/TR/WebIDL/#idl-enums #}
    127 String string = {{argument.name}};
    128 if (!({{argument.enum_validation_expression}})) {
    129     {{throw_type_error(method,
    130           '"parameter %s (\'" + string + "\') is not a valid enum value."' %
    131               (argument.index + 1))}}
    132     return;
    133 }
    134 {% endif %}
    135 {% if argument.idl_type in ['Dictionary', 'Promise'] %}
    136 if (!{{argument.name}}.isUndefinedOrNull() && !{{argument.name}}.isObject()) {
    137     {{throw_type_error(method, '"parameter %s (\'%s\') is not an object."' %
    138                                (argument.index + 1, argument.name))}}
    139     return;
    140 }
    141 {% endif %}
    142 {% endmacro %}
    143 
    144 
    145 {######################################}
    146 {% macro cpp_method_call(method, v8_set_return_value, cpp_value) %}
    147 {% if method.is_call_with_script_state %}
    148 ScriptState* currentState = ScriptState::current();
    149 if (!currentState)
    150     return;
    151 ScriptState& state = *currentState;
    152 {% endif %}
    153 {% if method.is_call_with_execution_context %}
    154 ExecutionContext* scriptContext = getExecutionContext();
    155 {% endif %}
    156 {% if method.is_call_with_script_arguments %}
    157 RefPtr<ScriptArguments> scriptArguments(createScriptArguments(info, {{method.number_of_arguments}}));
    158 {% endif %}
    159 {% if method.idl_type == 'void' %}
    160 {{cpp_value}};
    161 {% elif method.is_call_with_script_state %}
    162 {# FIXME: consider always using a local variable #}
    163 {{method.cpp_type}} result = {{cpp_value}};
    164 {% endif %}
    165 {% if method.is_raises_exception %}
    166 if (exceptionState.throwIfNeeded())
    167     return;
    168 {% endif %}
    169 {% if method.is_call_with_script_state %}
    170 if (state.hadException()) {
    171     v8::Local<v8::Value> exception = state.exception();
    172     state.clearException();
    173     throwError(exception, info.GetIsolate());
    174     return;
    175 }
    176 {% endif %}
    177 {% if v8_set_return_value %}{{v8_set_return_value}};{% endif %}{# None for void #}
    178 {% endmacro %}
    179 
    180 
    181 {######################################}
    182 {% macro throw_type_error(method, error_message) %}
    183 {% if method.is_constructor %}
    184 throwTypeError(ExceptionMessages::failedToConstruct("{{interface_name}}", {{error_message}}), info.GetIsolate());
    185 {%- else %}
    186 throwTypeError(ExceptionMessages::failedToExecute("{{method.name}}", "{{interface_name}}", {{error_message}}), info.GetIsolate());
    187 {%- endif %}
    188 {% endmacro %}
    189 
    190 
    191 {##############################################################################}
    192 {% macro overload_resolution_method(overloads, world_suffix) %}
    193 static void {{overloads.name}}Method{{world_suffix}}(const v8::FunctionCallbackInfo<v8::Value>& info)
    194 {
    195     {% for method in overloads.methods %}
    196     if ({{method.overload_resolution_expression}}) {
    197         {{method.name}}{{method.overload_index}}Method{{world_suffix}}(info);
    198         return;
    199     }
    200     {% endfor %}
    201     {% if overloads.minimum_number_of_required_arguments %}
    202     ExceptionState exceptionState(ExceptionState::ExecutionContext, "{{overloads.name}}", "{{interface_name}}", info.Holder(), info.GetIsolate());
    203     if (UNLIKELY(info.Length() < {{overloads.minimum_number_of_required_arguments}})) {
    204         exceptionState.throwTypeError(ExceptionMessages::notEnoughArguments({{overloads.minimum_number_of_required_arguments}}, info.Length()));
    205         exceptionState.throwIfNeeded();
    206         return;
    207     }
    208     exceptionState.throwTypeError("No function was found that matched the signature provided.");
    209     exceptionState.throwIfNeeded();
    210     {% else %}
    211     {{throw_type_error(overloads, '"No function was found that matched the signature provided."')}}
    212     {% endif %}
    213 }
    214 {% endmacro %}
    215 
    216 
    217 {##############################################################################}
    218 {% macro method_callback(method, world_suffix) %}
    219 {% filter conditional(method.conditional_string) %}
    220 static void {{method.name}}MethodCallback{{world_suffix}}(const v8::FunctionCallbackInfo<v8::Value>& info)
    221 {
    222     TRACE_EVENT_SET_SAMPLING_STATE("Blink", "DOMMethod");
    223     {% if method.measure_as %}
    224     UseCounter::count(activeDOMWindow(), UseCounter::{{method.measure_as}});
    225     {% endif %}
    226     {% if method.deprecate_as %}
    227     UseCounter::countDeprecation(activeExecutionContext(), UseCounter::{{method.deprecate_as}});
    228     {% endif %}
    229     {% if world_suffix in method.activity_logging_world_list %}
    230     V8PerContextData* contextData = V8PerContextData::from(info.GetIsolate()->GetCurrentContext());
    231     if (contextData && contextData->activityLogger()) {
    232         {# FIXME: replace toVectorOfArguments with toNativeArguments(info, 0)
    233            and delete toVectorOfArguments #}
    234         Vector<v8::Handle<v8::Value> > loggerArgs = toNativeArguments<v8::Handle<v8::Value> >(info, 0);
    235         contextData->activityLogger()->log("{{interface_name}}.{{method.name}}", info.Length(), loggerArgs.data(), "Method");
    236     }
    237     {% endif %}
    238     {% if method.is_custom %}
    239     {{v8_class}}::{{method.name}}MethodCustom(info);
    240     {% else %}
    241     {{cpp_class}}V8Internal::{{method.name}}Method{{world_suffix}}(info);
    242     {% endif %}
    243     TRACE_EVENT_SET_SAMPLING_STATE("V8", "Execution");
    244 }
    245 {% endfilter %}
    246 {% endmacro %}
    247 
    248 
    249 {##############################################################################}
    250 {% macro origin_safe_method_getter(method, world_suffix) %}
    251 static void {{method.name}}OriginSafeMethodGetter{{world_suffix}}(const v8::PropertyCallbackInfo<v8::Value>& info)
    252 {
    253     {# FIXME: don't call GetIsolate() so often #}
    254     // This is only for getting a unique pointer which we can pass to privateTemplate.
    255     static int privateTemplateUniqueKey;
    256     WrapperWorldType currentWorldType = worldType(info.GetIsolate());
    257     V8PerIsolateData* data = V8PerIsolateData::from(info.GetIsolate());
    258     {# FIXME: 1 case of [DoNotCheckSignature] in Window.idl may differ #}
    259     v8::Handle<v8::FunctionTemplate> privateTemplate = data->privateTemplate(currentWorldType, &privateTemplateUniqueKey, {{cpp_class}}V8Internal::{{method.name}}MethodCallback{{world_suffix}}, v8Undefined(), v8::Signature::New(info.GetIsolate(), V8PerIsolateData::from(info.GetIsolate())->rawDOMTemplate(&{{v8_class}}::wrapperTypeInfo, currentWorldType)), {{method.number_of_required_or_variadic_arguments}});
    260 
    261     v8::Handle<v8::Object> holder = info.This()->FindInstanceInPrototypeChain({{v8_class}}::domTemplate(info.GetIsolate(), currentWorldType));
    262     if (holder.IsEmpty()) {
    263         // This is only reachable via |object.__proto__.func|, in which case it
    264         // has already passed the same origin security check
    265         v8SetReturnValue(info, privateTemplate->GetFunction());
    266         return;
    267     }
    268     {{cpp_class}}* imp = {{v8_class}}::toNative(holder);
    269     if (!BindingSecurity::shouldAllowAccessToFrame(imp->frame(), DoNotReportSecurityError)) {
    270         static int sharedTemplateUniqueKey;
    271         v8::Handle<v8::FunctionTemplate> sharedTemplate = data->privateTemplate(currentWorldType, &sharedTemplateUniqueKey, {{cpp_class}}V8Internal::{{method.name}}MethodCallback{{world_suffix}}, v8Undefined(), v8::Signature::New(info.GetIsolate(), V8PerIsolateData::from(info.GetIsolate())->rawDOMTemplate(&{{v8_class}}::wrapperTypeInfo, currentWorldType)), {{method.number_of_required_or_variadic_arguments}});
    272         v8SetReturnValue(info, sharedTemplate->GetFunction());
    273         return;
    274     }
    275 
    276     v8::Local<v8::Value> hiddenValue = info.This()->GetHiddenValue(v8::String::NewFromUtf8(info.GetIsolate(), "{{method.name}}", v8::String::kInternalizedString));
    277     if (!hiddenValue.IsEmpty()) {
    278         v8SetReturnValue(info, hiddenValue);
    279         return;
    280     }
    281 
    282     v8SetReturnValue(info, privateTemplate->GetFunction());
    283 }
    284 
    285 static void {{method.name}}OriginSafeMethodGetterCallback{{world_suffix}}(v8::Local<v8::String>, const v8::PropertyCallbackInfo<v8::Value>& info)
    286 {
    287     TRACE_EVENT_SET_SAMPLING_STATE("Blink", "DOMGetter");
    288     {{cpp_class}}V8Internal::{{method.name}}OriginSafeMethodGetter{{world_suffix}}(info);
    289     TRACE_EVENT_SET_SAMPLING_STATE("V8", "Execution");
    290 }
    291 {% endmacro %}
    292 
    293 
    294 {##############################################################################}
    295 {% macro generate_constructor(constructor) %}
    296 static void constructor{{constructor.overload_index}}(const v8::FunctionCallbackInfo<v8::Value>& info)
    297 {
    298     {% if interface_length and not constructor.overload_index %}
    299     {# FIXME: remove this UNLIKELY: constructors are heavy, so no difference. #}
    300     if (UNLIKELY(info.Length() < {{interface_length}})) {
    301         {{throw_type_error({'name': 'Constructor'},
    302             'ExceptionMessages::notEnoughArguments(%s, info.Length())' %
    303                 interface_length)}}
    304         return;
    305     }
    306     {% endif %}
    307     {% if is_constructor_raises_exception %}
    308     ExceptionState exceptionState(ExceptionState::ConstructionContext, "{{interface_name}}", info.Holder(), info.GetIsolate());
    309     {% endif %}
    310     {% for argument in constructor.arguments %}
    311     {{generate_argument(constructor, argument) | indent}}
    312     {% endfor %}
    313     {% if is_constructor_call_with_execution_context %}
    314     ExecutionContext* context = getExecutionContext();
    315     {% endif %}
    316     {% if is_constructor_call_with_document %}
    317     Document& document = *toDocument(getExecutionContext());
    318     {% endif %}
    319     RefPtr<{{cpp_class}}> impl = {{cpp_class}}::create({{constructor.argument_list | join(', ')}});
    320     v8::Handle<v8::Object> wrapper = info.Holder();
    321     {% if is_constructor_raises_exception %}
    322     if (exceptionState.throwIfNeeded())
    323         return;
    324     {% endif %}
    325 
    326     {# FIXME: Should probably be Independent unless [ActiveDOMObject]
    327               or [DependentLifetime]. #}
    328     V8DOMWrapper::associateObjectWithWrapper<{{v8_class}}>(impl.release(), &{{v8_class}}::wrapperTypeInfo, wrapper, info.GetIsolate(), WrapperConfiguration::Dependent);
    329     v8SetReturnValue(info, wrapper);
    330 }
    331 {% endmacro %}
    332 
    333 
    334 {##############################################################################}
    335 {% macro named_constructor_callback(constructor) %}
    336 static void {{v8_class}}ConstructorCallback(const v8::FunctionCallbackInfo<v8::Value>& info)
    337 {
    338     if (!info.IsConstructCall()) {
    339         throwTypeError(ExceptionMessages::failedToConstruct("{{constructor.name}}", "Please use the 'new' operator, this DOM object constructor cannot be called as a function."), info.GetIsolate());
    340         return;
    341     }
    342 
    343     if (ConstructorMode::current() == ConstructorMode::WrapExistingObject) {
    344         v8SetReturnValue(info, info.Holder());
    345         return;
    346     }
    347 
    348     Document* document = currentDocument();
    349     ASSERT(document);
    350 
    351     // Make sure the document is added to the DOM Node map. Otherwise, the {{cpp_class}} instance
    352     // may end up being the only node in the map and get garbage-collected prematurely.
    353     toV8(document, info.Holder(), info.GetIsolate());
    354 
    355     {# FIXME: arguments #}
    356     {% set argument_list = ['*document'] %}
    357     RefPtr<{{cpp_class}}> impl = {{cpp_class}}::createForJSConstructor({{argument_list | join(', ')}});
    358     v8::Handle<v8::Object> wrapper = info.Holder();
    359 
    360     V8DOMWrapper::associateObjectWithWrapper<{{v8_class}}>(impl.release(), &{{v8_class}}Constructor::wrapperTypeInfo, wrapper, info.GetIsolate(), WrapperConfiguration::Dependent);
    361     v8SetReturnValue(info, wrapper);
    362 }
    363 {% endmacro %}
    364