1{##############################################################################}
2{% macro attribute_getter(attribute, world_suffix) %}
3{% filter conditional(attribute.conditional_string) %}
4static void {{attribute.name}}AttributeGetter{{world_suffix}}(
5{%- if attribute.is_expose_js_accessors %}
6const v8::FunctionCallbackInfo<v8::Value>& info
7{%- else %}
8const v8::PropertyCallbackInfo<v8::Value>& info
9{%- endif %})
10{
11    {% if attribute.is_reflect and not attribute.is_url
12          and attribute.idl_type == 'DOMString' and is_node
13          and not attribute.is_implemented_in_private_script %}
14    {% set cpp_class, v8_class = 'Element', 'V8Element' %}
15    {% endif %}
16    {# holder #}
17    {% if not attribute.is_static %}
18    v8::Handle<v8::Object> holder = info.Holder();
19    {% endif %}
20    {# impl #}
21    {% if attribute.cached_attribute_validation_method %}
22    v8::Handle<v8::String> propertyName = v8AtomicString(info.GetIsolate(), "{{attribute.name}}");
23    {{cpp_class}}* impl = {{v8_class}}::toImpl(holder);
24    if (!impl->{{attribute.cached_attribute_validation_method}}()) {
25        v8::Handle<v8::Value> v8Value = V8HiddenValue::getHiddenValue(info.GetIsolate(), holder, propertyName);
26        if (!v8Value.IsEmpty()) {
27            v8SetReturnValue(info, v8Value);
28            return;
29        }
30    }
31    {% elif not attribute.is_static %}
32    {{cpp_class}}* impl = {{v8_class}}::toImpl(holder);
33    {% endif %}
34    {% if interface_name == 'Window' and attribute.idl_type == 'EventHandler' %}
35    if (!impl->document())
36        return;
37    {% endif %}
38    {# Local variables #}
39    {% if attribute.is_call_with_execution_context %}
40    ExecutionContext* executionContext = currentExecutionContext(info.GetIsolate());
41    {% endif %}
42    {% if attribute.is_call_with_script_state %}
43    ScriptState* scriptState = ScriptState::current(info.GetIsolate());
44    {% endif %}
45    {% if attribute.is_check_security_for_node or
46          attribute.is_getter_raises_exception %}
47    ExceptionState exceptionState(ExceptionState::GetterContext, "{{attribute.name}}", "{{interface_name}}", holder, info.GetIsolate());
48    {% endif %}
49    {% if attribute.is_explicit_nullable %}
50    bool isNull = false;
51    {% endif %}
52    {% if attribute.is_implemented_in_private_script %}
53    {{attribute.cpp_type}} result{{attribute.cpp_type_initializer}};
54    if (!{{attribute.cpp_value_original}})
55        return;
56    {% elif attribute.cpp_value_original %}
57    {{attribute.cpp_type}} {{attribute.cpp_value}}({{attribute.cpp_value_original}});
58    {% endif %}
59    {# Checks #}
60    {% if attribute.is_getter_raises_exception %}
61    if (UNLIKELY(exceptionState.throwIfNeeded()))
62        return;
63    {% endif %}
64    {% if attribute.is_check_security_for_node %}
65    if (!BindingSecurity::shouldAllowAccessToNode(info.GetIsolate(), {{attribute.cpp_value}}, exceptionState)) {
66        v8SetReturnValueNull(info);
67        exceptionState.throwIfNeeded();
68        return;
69    }
70    {% endif %}
71    {% if attribute.reflect_only %}
72    {{release_only_check(attribute.reflect_only, attribute.reflect_missing,
73                         attribute.reflect_invalid, attribute.reflect_empty,
74                         attribute.cpp_value)
75      | indent}}
76    {% endif %}
77    {% if attribute.is_explicit_nullable %}
78    if (isNull) {
79        v8SetReturnValueNull(info);
80        return;
81    }
82    {% endif %}
83    {% if attribute.cached_attribute_validation_method %}
84    V8HiddenValue::setHiddenValue(info.GetIsolate(), holder, propertyName, {{attribute.cpp_value_to_v8_value}});
85    {% endif %}
86    {# v8SetReturnValue #}
87    {% if attribute.is_keep_alive_for_gc %}
88    if ({{attribute.cpp_value}} && DOMDataStore::setReturnValueFromWrapper{{world_suffix}}<V8{{attribute.idl_type}}>(info.GetReturnValue(), {{attribute.cpp_value}}.get()))
89        return;
90    v8::Handle<v8::Value> wrapper = toV8({{attribute.cpp_value}}.get(), holder, info.GetIsolate());
91    if (!wrapper.IsEmpty()) {
92        V8HiddenValue::setHiddenValue(info.GetIsolate(), holder, v8AtomicString(info.GetIsolate(), "{{attribute.name}}"), wrapper);
93        {{attribute.v8_set_return_value}};
94    }
95    {% elif world_suffix %}
96    {{attribute.v8_set_return_value_for_main_world}};
97    {% else %}
98    {{attribute.v8_set_return_value}};
99    {% endif %}
100}
101{% endfilter %}
102{% endmacro %}
103
104{######################################}
105{% macro release_only_check(reflect_only_values, reflect_missing,
106                            reflect_invalid, reflect_empty, cpp_value) %}
107{# Attribute is limited to only known values: check that the attribute value is
108   one of those. If not, set it to the empty string.
109   http://www.whatwg.org/specs/web-apps/current-work/#limited-to-only-known-values #}
110{% if reflect_empty %}
111if ({{cpp_value}}.isNull()) {
112{% if reflect_missing %}
113    {{cpp_value}} = "{{reflect_missing}}";
114{% else %}
115    ;
116{% endif %}
117} else if ({{cpp_value}}.isEmpty()) {
118    {{cpp_value}} = "{{reflect_empty}}";
119{% else %}
120if ({{cpp_value}}.isEmpty()) {
121{# FIXME: should use [ReflectEmpty] instead; need to change IDL files #}
122{% if reflect_missing %}
123    {{cpp_value}} = "{{reflect_missing}}";
124{% else %}
125    ;
126{% endif %}
127{% endif %}
128{% for value in reflect_only_values %}
129} else if (equalIgnoringCase({{cpp_value}}, "{{value}}")) {
130    {{cpp_value}} = "{{value}}";
131{% endfor %}
132} else {
133    {{cpp_value}} = "{{reflect_invalid}}";
134}
135{% endmacro %}
136
137
138{##############################################################################}
139{% macro attribute_getter_callback(attribute, world_suffix) %}
140{% filter conditional(attribute.conditional_string) %}
141static void {{attribute.name}}AttributeGetterCallback{{world_suffix}}(
142{%- if attribute.is_expose_js_accessors %}
143const v8::FunctionCallbackInfo<v8::Value>& info
144{%- else %}
145v8::Local<v8::String>, const v8::PropertyCallbackInfo<v8::Value>& info
146{%- endif %})
147{
148    TRACE_EVENT_SET_SAMPLING_STATE("blink", "DOMGetter");
149    {% if attribute.deprecate_as %}
150    UseCounter::countDeprecation(callingExecutionContext(info.GetIsolate()), UseCounter::{{attribute.deprecate_as}});
151    {% endif %}
152    {% if attribute.measure_as %}
153    UseCounter::count(callingExecutionContext(info.GetIsolate()), UseCounter::{{attribute.measure_as}});
154    {% endif %}
155    {% if world_suffix in attribute.activity_logging_world_list_for_getter %}
156    ScriptState* scriptState = ScriptState::from(info.GetIsolate()->GetCurrentContext());
157    V8PerContextData* contextData = scriptState->perContextData();
158    {% if attribute.activity_logging_world_check %}
159    if (scriptState->world().isIsolatedWorld() && contextData && contextData->activityLogger())
160    {% else %}
161    if (contextData && contextData->activityLogger())
162    {% endif %}
163        contextData->activityLogger()->logGetter("{{interface_name}}.{{attribute.name}}");
164    {% endif %}
165    {% if attribute.has_custom_getter %}
166    {{v8_class}}::{{attribute.name}}AttributeGetterCustom(info);
167    {% else %}
168    {{cpp_class}}V8Internal::{{attribute.name}}AttributeGetter{{world_suffix}}(info);
169    {% endif %}
170    TRACE_EVENT_SET_SAMPLING_STATE("v8", "V8Execution");
171}
172{% endfilter %}
173{% endmacro %}
174
175
176{##############################################################################}
177{% macro constructor_getter_callback(attribute, world_suffix) %}
178{% filter conditional(attribute.conditional_string) %}
179static void {{attribute.name}}ConstructorGetterCallback{{world_suffix}}(v8::Local<v8::String> property, const v8::PropertyCallbackInfo<v8::Value>& info)
180{
181    TRACE_EVENT_SET_SAMPLING_STATE("blink", "DOMGetter");
182    {% if attribute.deprecate_as %}
183    UseCounter::countDeprecation(callingExecutionContext(info.GetIsolate()), UseCounter::{{attribute.deprecate_as}});
184    {% endif %}
185    {% if attribute.measure_as %}
186    UseCounter::count(callingExecutionContext(info.GetIsolate()), UseCounter::{{attribute.measure_as}});
187    {% endif %}
188    {{cpp_class}}V8Internal::{{cpp_class}}ConstructorGetter{{world_suffix}}(property, info);
189    TRACE_EVENT_SET_SAMPLING_STATE("v8", "V8Execution");
190}
191{% endfilter %}
192{% endmacro %}
193
194
195{##############################################################################}
196{% macro attribute_setter(attribute, world_suffix) %}
197{% filter conditional(attribute.conditional_string) %}
198static void {{attribute.name}}AttributeSetter{{world_suffix}}(
199{%- if attribute.is_expose_js_accessors %}
200v8::Local<v8::Value> v8Value, const v8::FunctionCallbackInfo<v8::Value>& info
201{%- else %}
202v8::Local<v8::Value> v8Value, const v8::PropertyCallbackInfo<void>& info
203{%- endif %})
204{
205    {% if attribute.is_reflect and attribute.idl_type == 'DOMString'
206          and is_node and not attribute.is_implemented_in_private_script %}
207    {% set cpp_class, v8_class = 'Element', 'V8Element' %}
208    {% endif %}
209    {# Local variables #}
210    {% if not attribute.is_static %}
211    v8::Handle<v8::Object> holder = info.Holder();
212    {% endif %}
213    {% if attribute.has_setter_exception_state %}
214    ExceptionState exceptionState(ExceptionState::SetterContext, "{{attribute.name}}", "{{interface_name}}", holder, info.GetIsolate());
215    {% endif %}
216    {# Type checking #}
217    {% if attribute.has_type_checking_interface %}
218    {# Type checking for interface types (if interface not implemented, throw
219       TypeError), per http://www.w3.org/TR/WebIDL/#es-interface #}
220    if ({% if attribute.is_nullable %}!isUndefinedOrNull(v8Value) && {% endif %}!V8{{attribute.idl_type}}::hasInstance(v8Value, info.GetIsolate())) {
221        exceptionState.throwTypeError("The provided value is not of type '{{attribute.idl_type}}'.");
222        exceptionState.throwIfNeeded();
223        return;
224    }
225    {% endif %}
226    {# impl #}
227    {% if attribute.put_forwards %}
228    {{cpp_class}}* proxyImpl = {{v8_class}}::toImpl(holder);
229    {{attribute.cpp_type}} impl = WTF::getPtr(proxyImpl->{{attribute.name}}());
230    if (!impl)
231        return;
232    {% elif not attribute.is_static %}
233    {{cpp_class}}* impl = {{v8_class}}::toImpl(holder);
234    {% endif %}
235    {% if attribute.idl_type == 'EventHandler' and interface_name == 'Window' %}
236    if (!impl->document())
237        return;
238    {% endif %}
239    {# Convert JS value to C++ value #}
240    {% if attribute.idl_type != 'EventHandler' %}
241    {{attribute.v8_value_to_local_cpp_value}};
242    {% elif not is_node %}{# EventHandler hack #}
243    moveEventListenerToNewWrapper(holder, {{attribute.event_handler_getter_expression}}, v8Value, {{v8_class}}::eventListenerCacheIndex, info.GetIsolate());
244    {% endif %}
245    {# Type checking, possibly throw a TypeError, per:
246       http://www.w3.org/TR/WebIDL/#es-type-mapping #}
247    {% if attribute.has_type_checking_unrestricted %}
248    {# Non-finite floating point values (NaN, +Infinity orInfinity), per:
249       http://heycam.github.io/webidl/#es-float
250       http://heycam.github.io/webidl/#es-double #}
251    if (!std::isfinite(cppValue)) {
252        exceptionState.throwTypeError("The provided {{attribute.idl_type}} value is non-finite.");
253        exceptionState.throwIfNeeded();
254        return;
255    }
256    {% elif attribute.enum_validation_expression %}
257    {# Setter ignores invalid enum values:
258       http://www.w3.org/TR/WebIDL/#idl-enums #}
259    String string = cppValue;
260    if (!({{attribute.enum_validation_expression}}))
261        return;
262    {% endif %}
263    {# Pre-set context #}
264    {% if attribute.is_custom_element_callbacks or
265          (attribute.is_reflect and
266           not(attribute.idl_type == 'DOMString' and is_node)) %}
267    {# Skip on compact node DOMString getters #}
268    CustomElementProcessingStack::CallbackDeliveryScope deliveryScope;
269    {% endif %}
270    {% if attribute.is_call_with_execution_context or
271          attribute.is_setter_call_with_execution_context %}
272    ExecutionContext* executionContext = currentExecutionContext(info.GetIsolate());
273    {% endif %}
274    {# Set #}
275    {{attribute.cpp_setter}};
276    {# Post-set #}
277    {% if attribute.is_setter_raises_exception %}
278    exceptionState.throwIfNeeded();
279    {% endif %}
280    {% if attribute.cached_attribute_validation_method %}
281    V8HiddenValue::deleteHiddenValue(info.GetIsolate(), holder, v8AtomicString(info.GetIsolate(), "{{attribute.name}}")); // Invalidate the cached value.
282    {% endif %}
283}
284{% endfilter %}
285{% endmacro %}
286
287
288{##############################################################################}
289{% macro attribute_setter_callback(attribute, world_suffix) %}
290{% filter conditional(attribute.conditional_string) %}
291static void {{attribute.name}}AttributeSetterCallback{{world_suffix}}(
292{%- if attribute.is_expose_js_accessors %}
293const v8::FunctionCallbackInfo<v8::Value>& info
294{%- else %}
295v8::Local<v8::String>, v8::Local<v8::Value> v8Value, const v8::PropertyCallbackInfo<void>& info
296{%- endif %})
297{
298    {% if attribute.is_expose_js_accessors %}
299    v8::Local<v8::Value> v8Value = info[0];
300    {% endif %}
301    TRACE_EVENT_SET_SAMPLING_STATE("blink", "DOMSetter");
302    {% if attribute.deprecate_as %}
303    UseCounter::countDeprecation(callingExecutionContext(info.GetIsolate()), UseCounter::{{attribute.deprecate_as}});
304    {% endif %}
305    {% if attribute.measure_as %}
306    UseCounter::count(callingExecutionContext(info.GetIsolate()), UseCounter::{{attribute.measure_as}});
307    {% endif %}
308    {% if world_suffix in attribute.activity_logging_world_list_for_setter %}
309    ScriptState* scriptState = ScriptState::from(info.GetIsolate()->GetCurrentContext());
310    V8PerContextData* contextData = scriptState->perContextData();
311    {% if attribute.activity_logging_world_check %}
312    if (scriptState->world().isIsolatedWorld() && contextData && contextData->activityLogger()) {
313    {% else %}
314    if (contextData && contextData->activityLogger()) {
315    {% endif %}
316        contextData->activityLogger()->logSetter("{{interface_name}}.{{attribute.name}}", v8Value);
317    }
318    {% endif %}
319    {% if attribute.is_custom_element_callbacks or attribute.is_reflect %}
320    CustomElementProcessingStack::CallbackDeliveryScope deliveryScope;
321    {% endif %}
322    {% if attribute.has_custom_setter %}
323    {{v8_class}}::{{attribute.name}}AttributeSetterCustom(v8Value, info);
324    {% else %}
325    {{cpp_class}}V8Internal::{{attribute.name}}AttributeSetter{{world_suffix}}(v8Value, info);
326    {% endif %}
327    TRACE_EVENT_SET_SAMPLING_STATE("v8", "V8Execution");
328}
329{% endfilter %}
330{% endmacro %}
331
332
333{##############################################################################}
334{% macro attribute_getter_implemented_in_private_script(attribute) %}
335bool {{v8_class}}::PrivateScript::{{attribute.name}}AttributeGetter(LocalFrame* frame, {{cpp_class}}* holderImpl, {{attribute.cpp_type}}* result)
336{
337    if (!frame)
338        return false;
339    v8::HandleScope handleScope(toIsolate(frame));
340    ScriptForbiddenScope::AllowUserAgentScript script;
341    v8::Handle<v8::Context> contextInPrivateScript = toV8Context(frame, DOMWrapperWorld::privateScriptIsolatedWorld());
342    if (contextInPrivateScript.IsEmpty())
343        return false;
344    ScriptState* scriptState = ScriptState::from(contextInPrivateScript);
345    ScriptState* scriptStateInUserScript = ScriptState::forMainWorld(frame);
346    if (!scriptState->executionContext())
347        return false;
348
349    ScriptState::Scope scope(scriptState);
350    v8::Handle<v8::Value> holder = toV8(holderImpl, scriptState->context()->Global(), scriptState->isolate());
351
352    ExceptionState exceptionState(ExceptionState::GetterContext, "{{attribute.name}}", "{{cpp_class}}", scriptState->context()->Global(), scriptState->isolate());
353    v8::Handle<v8::Value> v8Value = PrivateScriptRunner::runDOMAttributeGetter(scriptState, scriptStateInUserScript, "{{cpp_class}}", "{{attribute.name}}", holder);
354    if (v8Value.IsEmpty())
355        return false;
356    {{attribute.private_script_v8_value_to_local_cpp_value}};
357    RELEASE_ASSERT(!exceptionState.hadException());
358    *result = cppValue;
359    return true;
360}
361{% endmacro %}
362
363
364{% macro attribute_setter_implemented_in_private_script(attribute) %}
365bool {{v8_class}}::PrivateScript::{{attribute.name}}AttributeSetter(LocalFrame* frame, {{cpp_class}}* holderImpl, {{attribute.argument_cpp_type}} cppValue)
366{
367    if (!frame)
368        return false;
369    v8::HandleScope handleScope(toIsolate(frame));
370    ScriptForbiddenScope::AllowUserAgentScript script;
371    v8::Handle<v8::Context> contextInPrivateScript = toV8Context(frame, DOMWrapperWorld::privateScriptIsolatedWorld());
372    if (contextInPrivateScript.IsEmpty())
373        return false;
374    ScriptState* scriptState = ScriptState::from(contextInPrivateScript);
375    ScriptState* scriptStateInUserScript = ScriptState::forMainWorld(frame);
376    if (!scriptState->executionContext())
377        return false;
378
379    ScriptState::Scope scope(scriptState);
380    v8::Handle<v8::Value> holder = toV8(holderImpl, scriptState->context()->Global(), scriptState->isolate());
381
382    ExceptionState exceptionState(ExceptionState::SetterContext, "{{attribute.name}}", "{{cpp_class}}", scriptState->context()->Global(), scriptState->isolate());
383    return PrivateScriptRunner::runDOMAttributeSetter(scriptState, scriptStateInUserScript, "{{cpp_class}}", "{{attribute.name}}", holder, {{attribute.private_script_cpp_value_to_v8_value}});
384}
385{% endmacro %}
386
387
388{##############################################################################}
389{% macro attribute_configuration(attribute) %}
390{% set getter_callback =
391       '%sV8Internal::%sAttributeGetterCallback' %
392            (cpp_class, attribute.name)
393       if not attribute.constructor_type else
394       ('%sV8Internal::%sConstructorGetterCallback' %
395            (cpp_class, attribute.name)
396        if attribute.needs_constructor_getter_callback else
397       '{0}V8Internal::{0}ConstructorGetter'.format(cpp_class)) %}
398{% set getter_callback_for_main_world =
399       '%sV8Internal::%sAttributeGetterCallbackForMainWorld' %
400            (cpp_class, attribute.name)
401       if attribute.is_per_world_bindings else '0' %}
402{% set setter_callback = attribute.setter_callback %}
403{% set setter_callback_for_main_world =
404       '%sV8Internal::%sAttributeSetterCallbackForMainWorld' %
405           (cpp_class, attribute.name)
406       if attribute.is_per_world_bindings and
407          (not attribute.is_read_only or attribute.put_forwards) else '0' %}
408{% set wrapper_type_info =
409       'const_cast<WrapperTypeInfo*>(&V8%s::wrapperTypeInfo)' %
410            attribute.constructor_type
411        if attribute.constructor_type else '0' %}
412{% set access_control = 'static_cast<v8::AccessControl>(%s)' %
413                        ' | '.join(attribute.access_control_list) %}
414{% set property_attribute = 'static_cast<v8::PropertyAttribute>(%s)' %
415                            ' | '.join(attribute.property_attributes) %}
416{% set only_exposed_to_private_script = 'V8DOMConfiguration::OnlyExposedToPrivateScript' if attribute.only_exposed_to_private_script else 'V8DOMConfiguration::ExposedToAllScripts' %}
417{% set on_prototype = 'V8DOMConfiguration::OnPrototype'
418       if interface_name == 'Window' and attribute.idl_type == 'EventHandler'
419       else 'V8DOMConfiguration::OnInstance' %}
420{% set attribute_configuration_list = [
421       '"%s"' % attribute.name,
422       getter_callback,
423       setter_callback,
424       getter_callback_for_main_world,
425       setter_callback_for_main_world,
426       wrapper_type_info,
427       access_control,
428       property_attribute,
429       only_exposed_to_private_script,
430   ] %}
431{% if not attribute.is_expose_js_accessors %}
432{% set attribute_configuration_list = attribute_configuration_list
433                                    + [on_prototype] %}
434{% endif %}
435{{'{'}}{{attribute_configuration_list | join(', ')}}{{'}'}}
436{%- endmacro %}
437