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