• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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