1{% filter format_blink_cpp_source_code %}
2
3{% include 'copyright_block.txt' %}
4#include "{{this_include_header_path}}"
5
6#include <algorithm>
7
8{% for filename in cpp_includes if filename != '%s.h' % cpp_class_or_partial %}
9#include "{{filename}}"
10{% endfor %}
11
12namespace blink {
13{% set dom_template = '%s::DomTemplate' % v8_class if not is_array_buffer_or_view else 'nullptr' %}
14{% set parent_wrapper_type_info = 'V8%s::GetWrapperTypeInfo()' % parent_interface
15                                  if parent_interface else 'nullptr' %}
16{% set active_scriptwrappable_inheritance =
17    'kInheritFromActiveScriptWrappable'
18    if active_scriptwrappable else
19    'kNotInheritFromActiveScriptWrappable' %}
20
21{% set wrapper_type_info_const = '' if has_partial_interface else 'const ' %}
22{% if not is_partial %}
23// Suppress warning: global constructors, because struct WrapperTypeInfo is trivial
24// and does not depend on another global objects.
25#if defined(COMPONENT_BUILD) && defined(WIN32) && defined(__clang__)
26#pragma clang diagnostic push
27#pragma clang diagnostic ignored "-Wglobal-constructors"
28#endif
29{{wrapper_type_info_const}}WrapperTypeInfo {{snake_case_v8_class}}_wrapper_type_info = {
30    gin::kEmbedderBlink,
31    {{dom_template}},
32    {{install_conditional_features_func or 'nullptr'}},
33    "{{interface_name}}",
34    {{parent_wrapper_type_info}},
35    WrapperTypeInfo::kWrapperTypeObjectPrototype,
36    WrapperTypeInfo::{{wrapper_class_id}},
37    WrapperTypeInfo::{{active_scriptwrappable_inheritance}},
38};
39#if defined(COMPONENT_BUILD) && defined(WIN32) && defined(__clang__)
40#pragma clang diagnostic pop
41#endif
42
43{% if not is_typed_array_type %}
44// This static member must be declared by DEFINE_WRAPPERTYPEINFO in {{cpp_class}}.h.
45// For details, see the comment of DEFINE_WRAPPERTYPEINFO in
46// platform/bindings/ScriptWrappable.h.
47const WrapperTypeInfo& {{cpp_class}}::wrapper_type_info_ = {{snake_case_v8_class}}_wrapper_type_info;
48{% endif %}
49
50{% if active_scriptwrappable %}
51// [ActiveScriptWrappable]
52static_assert(
53    std::is_base_of<ActiveScriptWrappableBase, {{cpp_class}}>::value,
54    "{{cpp_class}} does not inherit from ActiveScriptWrappable<>, but specifying "
55    "[ActiveScriptWrappable] extended attribute in the IDL file.  "
56    "Be consistent.");
57static_assert(
58    !std::is_same<decltype(&{{cpp_class}}::HasPendingActivity),
59                  decltype(&ScriptWrappable::HasPendingActivity)>::value,
60    "{{cpp_class}} is not overriding hasPendingActivity(), but is specifying "
61    "[ActiveScriptWrappable] extended attribute in the IDL file.  "
62    "Be consistent.");
63{% else %}
64// not [ActiveScriptWrappable]
65static_assert(
66    !std::is_base_of<ActiveScriptWrappableBase, {{cpp_class}}>::value,
67    "{{cpp_class}} inherits from ActiveScriptWrappable<>, but is not specifying "
68    "[ActiveScriptWrappable] extended attribute in the IDL file.  "
69    "Be consistent.");
70static_assert(
71    std::is_same<decltype(&{{cpp_class}}::HasPendingActivity),
72                 decltype(&ScriptWrappable::HasPendingActivity)>::value,
73    "{{cpp_class}} is overriding hasPendingActivity(), but is not specifying "
74    "[ActiveScriptWrappable] extended attribute in the IDL file.  "
75    "Be consistent.");
76{% endif %}
77
78{% endif %}{# not is_partial #}
79{% if not is_array_buffer_or_view %}
80namespace {{internal_namespace}} {
81{% if has_partial_interface %}
82{% for method in methods if method.overloads and method.overloads.has_partial_overloads %}
83static void (*{{method.name}}MethodForPartialInterface)(const v8::FunctionCallbackInfo<v8::Value>&) = 0;
84{% endfor %}
85{% endif %}
86
87{##############################################################################}
88{# Attributes #}
89{% from 'attributes.cc.tmpl' import attribute_getter, attribute_setter,
90       with context %}
91{% for attribute in attributes %}
92{% for world_suffix in attribute.world_suffixes %}
93{% if attribute.private_property_is_shared_between_getter_and_setter %}
94// Define a private property key shared between getter and setter.
95static const V8PrivateProperty::SymbolKey kPrivateProperty{{attribute.camel_case_name}};
96{% endif %}
97
98{% if attribute.does_generate_getter %}
99{{attribute_getter(attribute, world_suffix)}}
100{% endif %}
101{% if attribute.does_generate_setter %}
102{{attribute_setter(attribute, world_suffix)}}
103{% endif %}
104{% endfor %}
105{% endfor %}
106{##############################################################################}
107{# Methods #}
108{% from 'methods.cc.tmpl' import generate_method, overload_resolution_method,
109      origin_safe_method_getter, generate_constructor,
110      runtime_determined_length_method, runtime_determined_maxarg_method
111      with context %}
112{% for method in methods %}
113{% for world_suffix in method.world_suffixes %}
114{% if not method.is_custom and method.visible %}
115{{generate_method(method, world_suffix)}}
116{% endif %}
117{% if method.overloads and method.overloads.visible %}
118{% if method.overloads.runtime_determined_lengths %}
119{{runtime_determined_length_method(method.overloads)}}
120{% endif %}
121{% if method.overloads.runtime_determined_maxargs %}
122{{runtime_determined_maxarg_method(method.overloads)}}
123{% endif %}
124{{overload_resolution_method(method.overloads, world_suffix)}}
125{% endif %}
126{% if method.is_cross_origin and method.visible and
127      (not method.overload_index or method.overloads) %}
128{{origin_safe_method_getter(method, world_suffix)}}
129{% endif %}
130{% endfor %}
131{% endfor %}
132{% if iterator_method %}
133{{generate_method(iterator_method)}}
134{% endif %}
135{# Constructors #}
136{% for constructor in constructors %}
137{{generate_constructor(constructor)}}
138{% endfor %}
139{% block overloaded_constructor %}{% endblock %}
140{% block constructor_callback %}{% endblock %}
141{# Special operations (methods) #}
142{% block named_property_getter %}{% endblock %}
143{% block named_property_setter %}{% endblock %}
144{% block named_property_deleter %}{% endblock %}
145{% block named_property_query %}{% endblock %}
146{% block named_property_descriptor %}{% endblock %}
147{% block named_property_enumerator %}{% endblock %}
148{% block indexed_property_getter %}{% endblock %}
149{% block indexed_property_descriptor %}{% endblock %}
150{% block indexed_property_setter %}{% endblock %}
151{% block indexed_property_deleter %}{% endblock %}
152{##############################################################################}
153{% if has_access_check_callbacks and not is_partial and has_cross_origin_named_enumerator %}
154static const struct {
155  using GetterCallback = void(*)(const v8::PropertyCallbackInfo<v8::Value>&);
156  using SetterCallback = void(*)(v8::Local<v8::Value>, const V8CrossOriginCallbackInfo&);
157
158  const char* const name;
159  const GetterCallback getter;
160  const SetterCallback setter;
161} kCrossOriginAttributeTable[] = {
162  {% for attribute in attributes if attribute.has_cross_origin_getter or attribute.has_cross_origin_setter %}
163  {
164    "{{attribute.name}}",
165    {% if attribute.has_cross_origin_getter %}
166    {% if attribute.has_custom_getter %}
167    {{v8_class}}::{{attribute.camel_case_name}}AttributeGetterCustom,
168    {% else %}
169    {{internal_namespace}}::{{attribute.camel_case_name}}AttributeGetter,
170    {% endif %}
171    {% else %}
172    nullptr,
173    {% endif %}
174    {%+ if attribute.has_cross_origin_setter %}&{{internal_namespace}}::{{attribute.camel_case_name}}AttributeSetter{% else %}nullptr{% endif %},
175  },
176  {% endfor %}
177};
178
179static const struct {
180  using ValueCallback = void(*)(const v8::PropertyCallbackInfo<v8::Value>&);
181
182  const char* const name;
183  const ValueCallback value;
184} kCrossOriginOperationTable[] = {
185  {% for method in methods if method.is_cross_origin and
186        (not method.overload_index or method.overloads) %}
187  {"{{method.name}}", &{{internal_namespace}}::{{method.camel_case_name}}OriginSafeMethodGetter},
188  {% endfor %}
189};
190{% endif %}
191{##############################################################################}
192}  // namespace {{internal_namespace}}
193
194{# Constants #}
195{% from 'constants.cc.tmpl' import constant_getter_callback with context %}
196{% for constant in constants | has_special_getter %}
197{{constant_getter_callback(constant)}}
198{% endfor %}
199
200{# Attributes #}
201{% from 'attributes.cc.tmpl' import constructor_getter_callback,
202       attribute_getter_callback, attribute_setter_callback with context %}
203{% for attribute in attributes %}
204{% for world_suffix in attribute.world_suffixes %}
205{% if not attribute.constructor_type %}
206{{attribute_getter_callback(attribute, world_suffix)}}
207{% else %}
208{{constructor_getter_callback(attribute, world_suffix)}}
209{% endif %}
210{% if attribute.has_setter %}
211{{attribute_setter_callback(attribute, world_suffix)}}
212{% endif %}
213{% endfor %}
214{% endfor %}
215
216{# Methods #}
217{% from 'methods.cc.tmpl' import origin_safe_method_getter_callback,
218      method_callback with context %}
219{% for method in methods %}
220{% for world_suffix in method.world_suffixes %}
221{% if not method.overload_index or method.overloads %}
222{# Document about the following condition: #}
223{# https://docs.google.com/document/d/1qBC7Therp437Jbt_QYAtNYMZs6zQ_7_tnMkNUG_ACqs/edit?usp=sharing #}
224{% if (method.overloads and method.overloads.visible and
225       (not method.overloads.has_partial_overloads or not is_partial)) or
226      (not method.overloads and method.visible) %}
227{# A single callback is generated for overloaded methods #}
228{# with considering partial overloads #}
229{{method_callback(method, world_suffix)}}
230{% endif %}
231{% endif %}
232{% if method.is_cross_origin and method.visible and
233     (not method.overload_index or method.overloads) %}
234{{origin_safe_method_getter_callback(method, world_suffix)}}
235{% endif %}
236{% endfor %}
237{% endfor %}
238{% if iterator_method %}
239{{method_callback(iterator_method)}}
240{% endif %}
241{# Special operations (methods) #}
242{% block named_property_getter_callback %}{% endblock %}
243{% block named_property_setter_callback %}{% endblock %}
244{% block named_property_deleter_callback %}{% endblock %}
245{% block named_property_query_callback %}{% endblock %}
246{% block named_property_enumerator_callback %}{% endblock %}
247{% block indexed_property_getter_callback %}{% endblock %}
248{% block indexed_property_descriptor_callback %}{% endblock %}
249{% block indexed_property_setter_callback %}{% endblock %}
250{% block indexed_property_deleter_callback %}{% endblock %}
251{% block indexed_property_definer_callback %}{% endblock %}
252
253{% if has_access_check_callbacks and not is_partial %}
254bool {{v8_class_or_partial}}::SecurityCheck(v8::Local<v8::Context> accessing_context, v8::Local<v8::Object> accessed_object, v8::Local<v8::Value> data) {
255  {% if interface_name == 'Window' %}
256  v8::Isolate* isolate = v8::Isolate::GetCurrent();
257  v8::Local<v8::Object> window = V8Window::FindInstanceInPrototypeChain(accessed_object, isolate);
258  if (window.IsEmpty())
259    return false;  // the frame is gone.
260
261  const DOMWindow* target_window = V8Window::ToImpl(window);
262  return BindingSecurity::ShouldAllowAccessTo(ToLocalDOMWindow(accessing_context), target_window, BindingSecurity::ErrorReportOption::kDoNotReport);
263  {% elif interface_name == 'Location' %}
264  {{cpp_class}}* impl = {{v8_class}}::ToImpl(accessed_object);
265  return BindingSecurity::ShouldAllowAccessTo(ToLocalDOMWindow(accessing_context), impl, BindingSecurity::ErrorReportOption::kDoNotReport);
266  {% else %}
267  #error "Unexpected security check for interface {{interface_name}}"
268  {% endif %}
269}
270
271{% if has_cross_origin_named_getter %}
272void {{v8_class_or_partial}}::CrossOriginNamedGetter(v8::Local<v8::Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
273  {{ runtime_timer_scope_disabled_by_default(runtime_call_stats.cross_origin_named_getter_counter) }}
274  if (!name->IsString())
275    return;
276  const AtomicString& property_name = ToCoreAtomicString(name.As<v8::String>());
277
278  for (const auto& attribute : {{internal_namespace}}::kCrossOriginAttributeTable) {
279    if (property_name == attribute.name && attribute.getter) {
280      attribute.getter(info);
281      return;
282    }
283  }
284  for (const auto& operation : {{internal_namespace}}::kCrossOriginOperationTable) {
285    if (property_name == operation.name) {
286      operation.value(info);
287      return;
288    }
289  }
290
291  {% if named_property_getter and named_property_getter.is_cross_origin %}
292  {% if named_property_getter.is_custom %}
293  {{v8_class}}::NamedPropertyGetterCustom(property_name, info);
294  {% else %}
295  {{internal_namespace}}::NamedPropertyGetter(property_name, info);
296  {% endif %}
297  {% else %}
298  // HTML 7.2.3.3 CrossOriginGetOwnPropertyHelper ( O, P )
299  // https://html.spec.whatwg.org/C/#crossorigingetownpropertyhelper-(-o,-p-)
300  // step 3. If P is "then", @@toStringTag, @@hasInstance, or
301  //   @@isConcatSpreadable, then return PropertyDescriptor{ [[Value]]:
302  //   undefined, [[Writable]]: false, [[Enumerable]]: false,
303  //   [[Configurable]]: true }.
304  if (property_name == "then") {
305    V8SetReturnValue(info, v8::Undefined(info.GetIsolate()));
306    return;
307  }
308
309  BindingSecurity::FailedAccessCheckFor(
310      info.GetIsolate(),
311      {{v8_class}}::GetWrapperTypeInfo(),
312      info.Holder());
313  {% endif %}
314}
315{% endif %}
316
317{% if has_cross_origin_named_setter %}
318void {{v8_class_or_partial}}::CrossOriginNamedSetter(v8::Local<v8::Name> name, v8::Local<v8::Value> value, const v8::PropertyCallbackInfo<v8::Value>& info) {
319  {{ runtime_timer_scope_disabled_by_default(runtime_call_stats.cross_origin_named_setter_counter) }}
320  if (!name->IsString())
321    return;
322  const AtomicString& property_name = ToCoreAtomicString(name.As<v8::String>());
323
324  for (const auto& attribute : {{internal_namespace}}::kCrossOriginAttributeTable) {
325    if (property_name == attribute.name && attribute.setter) {
326      attribute.setter(value, V8CrossOriginCallbackInfo(info));
327      return;
328    }
329  }
330
331  {# If there were no matches in the cross-origin attribute table, consider it
332     an access check failure: there are no custom named setters that are
333     accessible from a cross-origin context. #}
334
335  BindingSecurity::FailedAccessCheckFor(
336      info.GetIsolate(),
337      {{v8_class}}::GetWrapperTypeInfo(),
338      info.Holder());
339}
340{% endif %}
341
342{% if has_cross_origin_named_enumerator %}
343void {{v8_class_or_partial}}::CrossOriginNamedEnumerator(const v8::PropertyCallbackInfo<v8::Array>& info) {
344  Vector<String> names;
345  for (const auto& attribute : {{internal_namespace}}::kCrossOriginAttributeTable)
346    names.push_back(attribute.name);
347  for (const auto& operation : {{internal_namespace}}::kCrossOriginOperationTable)
348    names.push_back(operation.name);
349
350  // Use the current context as the creation context, as a cross-origin access
351  // may involve an object that does not have a creation context.
352  V8SetReturnValue(info,
353                   ToV8(names, info.GetIsolate()->GetCurrentContext()->Global(),
354                        info.GetIsolate()).As<v8::Array>());
355}
356{% endif %}
357
358{% if has_cross_origin_indexed_getter %}
359void {{v8_class_or_partial}}::CrossOriginIndexedGetter(uint32_t index, const v8::PropertyCallbackInfo<v8::Value>& info) {
360  {% if indexed_property_getter.is_custom %}
361  {{v8_class}}::IndexedPropertyGetterCustom(index, info);
362  {% else %}
363  {{internal_namespace}}::IndexedPropertyGetter(index, info);
364  {% endif %}
365}
366{% endif %}
367{% endif %}{# has_access_check_callbacks #}
368
369{% block visit_dom_wrapper %}{% endblock %}
370{##############################################################################}
371{% block install_methods %}
372{% from 'methods.cc.tmpl' import method_configuration with context %}
373{% if methods | has_method_configuration(is_partial) %}
374static constexpr V8DOMConfiguration::MethodConfiguration k{{v8_class}}Methods[] = {
375    {% for method in methods | has_method_configuration(is_partial) %}
376    {{method_configuration(method) | trim | indent(4)}},
377    {% endfor %}
378};
379
380{% endif %}
381{% endblock %}
382{% endif %}{# not is_array_buffer_or_view #}
383{##############################################################################}
384{% block named_constructor %}{% endblock %}
385{##############################################################################}
386{% block install_dom_template %}
387{% if not is_array_buffer_or_view %}
388{% from 'methods.cc.tmpl' import install_custom_signature,
389        method_configuration with context %}
390{% from 'attributes.cc.tmpl' import accessor_configuration,
391        attribute_configuration, install_attributes, install_interface_objects,
392        with context %}
393{% from 'constants.cc.tmpl' import install_constants,
394        constant_configuration with context %}
395{% if has_partial_interface or is_partial %}
396void {{v8_class_or_partial}}::Install{{v8_class}}Template(
397    v8::Isolate* isolate,
398    const DOMWrapperWorld& world,
399    v8::Local<v8::FunctionTemplate> interface_template) {
400{% else %}
401static void Install{{v8_class}}Template(
402    v8::Isolate* isolate,
403    const DOMWrapperWorld& world,
404    v8::Local<v8::FunctionTemplate> interface_template) {
405{% endif %}
406  // Initialize the interface object's template.
407  {% if is_partial %}
408  {{v8_class}}::Install{{v8_class}}Template(isolate, world, interface_template);
409  {% else %}
410  {% set parent_interface_template =
411         '%s::DomTemplateForNamedPropertiesObject(isolate, world)' % v8_class
412         if has_named_properties_object else
413         'V8%s::DomTemplate(isolate, world)' % parent_interface
414         if parent_interface else
415         'v8::Local<v8::FunctionTemplate>()' %}
416  V8DOMConfiguration::InitializeDOMInterfaceTemplate(isolate, interface_template, {{v8_class}}::GetWrapperTypeInfo()->interface_name, {{parent_interface_template}}, {{v8_class}}::kInternalFieldCount);
417  {% if constructors or has_custom_constructor or has_html_constructor %}
418  interface_template->SetCallHandler({{internal_namespace}}::ConstructorCallback);
419  interface_template->SetLength({{interface_length}});
420  {% endif %}
421  {% endif %}{# is_partial #}
422
423  {% if runtime_enabled_feature_name and not context_enabled_feature_name %}
424  if (!{{runtime_enabled_feature_name | runtime_enabled_function}}) {
425    return;
426  }
427  {% endif %}
428
429  v8::Local<v8::Signature> signature = v8::Signature::New(isolate, interface_template);
430  ALLOW_UNUSED_LOCAL(signature);
431  v8::Local<v8::ObjectTemplate> instance_template = interface_template->InstanceTemplate();
432  ALLOW_UNUSED_LOCAL(instance_template);
433  v8::Local<v8::ObjectTemplate> prototype_template = interface_template->PrototypeTemplate();
434  ALLOW_UNUSED_LOCAL(prototype_template);
435
436  {% if interface_name == 'Window' and not is_partial %}
437  prototype_template->SetInternalFieldCount(V8Window::kInternalFieldCount);
438  {% endif %}
439
440  {% if is_immutable_prototype %}
441  // Global object prototype chain consists of Immutable Prototype Exotic Objects
442  prototype_template->SetImmutableProto();
443  {% endif %}
444
445  {% if is_global %}
446  // Global objects are Immutable Prototype Exotic Objects
447  instance_template->SetImmutableProto();
448  {% endif %}
449
450  // Register IDL constants, attributes and operations.
451  {% if constants %}
452  {{install_constants() | trim | indent(2)}}
453  {% endif %}
454  {% if data_attributes %}
455  {{install_interface_objects(data_attributes, 'instance_template', 'prototype_template') | trim | indent(2)}}
456  {% endif %}
457  {% if accessors %}
458  {{install_attributes(accessors, 'instance_template', 'prototype_template', 'interface_template') | trim | indent(2)}}
459  {% endif %}
460  {% if methods | has_method_configuration(is_partial) %}
461  V8DOMConfiguration::InstallMethods(
462      isolate, world, instance_template, prototype_template, interface_template,
463      signature, k{{v8_class}}Methods, base::size(k{{v8_class}}Methods));
464  {% endif %}
465
466  {% if has_access_check_callbacks and not is_partial %}
467  // Cross-origin access check
468  {% set cross_origin_named_getter = '%s::CrossOriginNamedGetter' % v8_class_or_partial if has_cross_origin_named_getter else 'nullptr' %}
469  {% set cross_origin_named_setter = '%s::CrossOriginNamedSetter' % v8_class_or_partial if has_cross_origin_named_setter else 'nullptr' %}
470  {% set cross_origin_named_enumerator = '%s::CrossOriginNamedEnumerator' % v8_class_or_partial if has_cross_origin_named_enumerator else 'nullptr' %}
471  {% set cross_origin_indexed_getter = '%s::CrossOriginIndexedGetter' % v8_class_or_partial if has_cross_origin_indexed_getter else 'nullptr' %}
472  instance_template->SetAccessCheckCallbackAndHandler(
473      {{v8_class_or_partial}}::SecurityCheck,
474      v8::NamedPropertyHandlerConfiguration(
475          {{cross_origin_named_getter}},
476          {{cross_origin_named_setter}},
477          nullptr,
478          nullptr,
479          {{cross_origin_named_enumerator}}),
480      v8::IndexedPropertyHandlerConfiguration({{cross_origin_indexed_getter}}),
481      v8::External::New(isolate, const_cast<WrapperTypeInfo*>({{v8_class}}::GetWrapperTypeInfo())));
482  {% endif %}
483
484  {% if (indexed_property_getter or named_property_getter) and not is_partial %}
485  // Indexed properties
486  {{install_indexed_property_handler('instance_template') | trim | indent(2)}}
487  {% endif %}
488  {% if named_property_getter and not is_partial and not has_named_properties_object %}
489  // Named properties
490  {{install_named_property_handler('instance_template') | trim | indent(2)}}
491  {% endif %}
492
493  {% if has_array_iterator and not is_partial %}
494  // Array iterator (@@iterator)
495  {%+ if is_global %}instance_template{% else %}prototype_template{% endif %}->SetIntrinsicDataProperty(v8::Symbol::GetIterator(isolate), v8::kArrayProto_values, v8::DontEnum);
496  {% if iterable %}
497  {% if is_global %}
498#error "iterable<V> on [Global] is currently unsupported."
499  {% endif %}
500  // For value iterators, the properties below must originally be set to the corresponding ones in %ArrayPrototype%.
501  // See https://heycam.github.io/webidl/#es-iterators.
502  prototype_template->SetIntrinsicDataProperty(V8AtomicString(isolate, "entries"), v8::kArrayProto_entries);
503  prototype_template->SetIntrinsicDataProperty(V8AtomicString(isolate, "forEach"), v8::kArrayProto_forEach);
504  prototype_template->SetIntrinsicDataProperty(V8AtomicString(isolate, "keys"), v8::kArrayProto_keys);
505  prototype_template->SetIntrinsicDataProperty(V8AtomicString(isolate, "values"), v8::kArrayProto_values);
506  {% endif %}
507  {% endif %}
508
509  {% if iterator_method and not iterator_method.runtime_enabled_feature_name %}
510  {% filter exposed(iterator_method.exposed_test) %}
511  {% set symbol_alias = '"%s"' % iterator_method_alias
512                        if iterator_method_alias else 'nullptr' %}
513  // Iterator (@@iterator)
514  static const V8DOMConfiguration::SymbolKeyedMethodConfiguration
515  kSymbolKeyedIteratorConfiguration = {
516      v8::Symbol::GetIterator,
517      {{symbol_alias}},
518      {{v8_class_or_partial}}::IteratorMethodCallback,
519      0,
520      v8::DontEnum,
521      V8DOMConfiguration::kOnPrototype,
522      V8DOMConfiguration::kCheckHolder,
523      V8DOMConfiguration::kDoNotCheckAccess,
524      V8DOMConfiguration::kHasSideEffect
525  };
526  V8DOMConfiguration::InstallMethod(
527      isolate, world, prototype_template, signature,
528      kSymbolKeyedIteratorConfiguration);
529  {% endfilter %}
530  {% endif %}
531
532  {% if interface_name == 'FileSystemDirectoryHandle' %}
533  // Temporary @@asyncIterator support for FileSystemDirectoryHandle
534  // TODO(https://crbug.com/1087157): Replace with proper bindings support.
535  static const V8DOMConfiguration::SymbolKeyedMethodConfiguration
536  kSymbolKeyedIteratorConfiguration = {
537      v8::Symbol::GetAsyncIterator,
538      "entries",
539      V8FileSystemDirectoryHandle::EntriesMethodCallback,
540      0,
541      v8::DontEnum,
542      V8DOMConfiguration::kOnPrototype,
543      V8DOMConfiguration::kCheckHolder,
544      V8DOMConfiguration::kDoNotCheckAccess,
545      V8DOMConfiguration::kHasSideEffect
546  };
547  V8DOMConfiguration::InstallMethod(
548      isolate, world, prototype_template, signature,
549      kSymbolKeyedIteratorConfiguration);
550  {% endif %}
551
552  {% if interface_name == 'Iterator' %}
553  // The WebIDL spec says when an interface has pair iterators the iterators it
554  // returns must be instances of the "default iterator object" whose
555  // [[Prototype]] points to an "iterator prototype object" whose
556  // [[Prototype]], on its turn, points to %IteratorPrototype%. next() must be
557  // implemented in the "iterator prototype object", while %IteratorPrototype%
558  // provides @@iterator.
559  // References:
560  // https://heycam.github.io/webidl/#es-default-iterator-object
561  // https://heycam.github.io/webidl/#es-iterator-prototype-object
562  //
563  // The iterators we return from interfaces that have pair interators adhere
564  // to the above by:
565  // - Adding the "next()" property to its prototype object.
566  // - Making the prototype object inherit from %IteratorPrototype% with the
567  //   hack below, which creates another function template with no prototype
568  //   and sets the "prototype" property of its function object.
569  //   When |interface_template|'s function object is created, its
570  //   prototype.__proto__ will point to the value of the "prototype" property
571  //   of |intrinsic_iterator_prototype_interface_template|, which is exactly
572  //   what we want.
573  //
574  // Finally, creating a FunctionTemplate here might look expensive since they
575  // have the same lifetime as their context, but:
576  // - |interface_template| is cached in V8PerIsolateData, so we create only one
577  //   FunctionTemplate per interface.
578  // - There is only one Iterator interface that creates this FunctionTemplate,
579  //   so there is no need to reuse this FunctionTemplate and register it in
580  //   V8PerIsolateData.
581  v8::Local<v8::FunctionTemplate> intrinsic_iterator_prototype_interface_template =
582      v8::FunctionTemplate::New(isolate);
583  intrinsic_iterator_prototype_interface_template->RemovePrototype();
584  intrinsic_iterator_prototype_interface_template->SetIntrinsicDataProperty(
585      V8AtomicString(isolate, "prototype"), v8::kIteratorPrototype);
586  interface_template->Inherit(intrinsic_iterator_prototype_interface_template);
587  {% endif %}
588
589  {% if interface_name == 'NativeFileSystemDirectoryIterator' %}
590  // Temporary @@asyncIterator support for FileSystemDirectoryHandle
591  // TODO(https://crbug.com/1087157): Replace with proper bindings support.
592  v8::Local<v8::FunctionTemplate> intrinsic_iterator_prototype_interface_template =
593      v8::FunctionTemplate::New(isolate);
594  intrinsic_iterator_prototype_interface_template->RemovePrototype();
595  intrinsic_iterator_prototype_interface_template->SetIntrinsicDataProperty(
596      V8AtomicString(isolate, "prototype"), v8::kAsyncIteratorPrototype);
597  interface_template->Inherit(intrinsic_iterator_prototype_interface_template);
598  {% endif %}
599
600  {% if interface_name == 'DOMException' %}
601  // The WebIDL spec states that DOMException objects have a few peculiarities.
602  // One of them is similar to what it mandates for Iterator objects when it
603  // comes to the inheritance chain. Instead of
604  //     DOMException -> prototype -> %ObjectPrototype%
605  // we have
606  //     DOMException -> prototype -> %ErrorPrototype% -> %ObjectPrototype%
607  // so that DOMException objects "inherit" toString() and a few properties
608  // from %ErrorPrototype%.
609  // See https://heycam.github.io/webidl/#es-DOMException-specialness.
610  //
611  // We achieve this with the same hack we use for Iterators: create a new
612  // function template with no prototype, set its "prototype" property to
613  // %ErrorPrototype% and make |interface_template| inherit from it. When
614  // |interface_template| is instantiated, its prototype.__proto__ will point to
615  // |intrinsic_error_prototype_interface_template|'s "prototype" property.
616  v8::Local<v8::FunctionTemplate> intrinsic_error_prototype_interface_template =
617      v8::FunctionTemplate::New(isolate);
618  intrinsic_error_prototype_interface_template->RemovePrototype();
619  intrinsic_error_prototype_interface_template->SetIntrinsicDataProperty(
620      V8AtomicString(isolate, "prototype"), v8::kErrorPrototype);
621  interface_template->Inherit(intrinsic_error_prototype_interface_template);
622  {% endif %}
623
624  {% if interface_name == 'Location' %}
625  // Symbol.toPrimitive
626  // Prevent author scripts to inject Symbol.toPrimitive property into location
627  // objects, also prevent the look-up of Symbol.toPrimitive through the
628  // prototype chain.
629  instance_template->Set(v8::Symbol::GetToPrimitive(isolate),
630                        v8::Undefined(isolate),
631                        static_cast<v8::PropertyAttribute>(
632                            v8::ReadOnly | v8::DontEnum | v8::DontDelete));
633  {% endif %}
634
635  {% if has_custom_legacy_call_as_function and not is_partial %}
636  instance_template->SetCallAsFunctionHandler({{v8_class}}::LegacyCallCustom);
637  {% endif %}
638
639  {% if interface_name == 'HTMLAllCollection' and not is_partial %}
640  // Needed for legacy support of document.all
641  instance_template->MarkAsUndetectable();
642  {% endif %}
643
644  // Custom signature
645  {% for method in methods | custom_registration(is_partial) %}
646  {% filter exposed(method.overloads.exposed_test_all
647                    if method.overloads else method.exposed_test) %}
648  {% set feature_name = method.overloads.runtime_enabled_all
649                        if method.overloads else method.runtime_enabled_feature_name %}
650  {% if not feature_name %}
651  {% if method.is_cross_origin %}
652  {{install_origin_safe_method(method, 'instance_template', 'prototype_template', 'interface_template', 'signature') | trim | indent(2)}}
653  {% else %}
654  {{install_custom_signature(method, 'instance_template', 'prototype_template', 'interface_template', 'signature') | trim | indent(2)}}
655  {% endif %}
656  {% endif %}
657  {% endfilter %}
658  {% endfor %}
659  {% if not has_partial_interface %}
660
661  {{v8_class_or_partial}}::InstallRuntimeEnabledFeaturesOnTemplate(
662      isolate, world, interface_template);
663  {% endif %}
664}
665
666void {{v8_class_or_partial}}::InstallRuntimeEnabledFeaturesOnTemplate(
667    v8::Isolate* isolate,
668    const DOMWrapperWorld& world,
669    v8::Local<v8::FunctionTemplate> interface_template) {
670  {% if runtime_enabled_feature_name and not context_enabled_feature_name %}
671  if (!{{runtime_enabled_feature_name | runtime_enabled_function}}) {
672    return;
673  }
674  {% endif %}
675
676  {% if is_partial %}
677  {{v8_class}}::InstallRuntimeEnabledFeaturesOnTemplate(isolate, world, interface_template);
678  {% endif %}
679
680  v8::Local<v8::Signature> signature = v8::Signature::New(isolate, interface_template);
681  ALLOW_UNUSED_LOCAL(signature);
682  v8::Local<v8::ObjectTemplate> instance_template = interface_template->InstanceTemplate();
683  ALLOW_UNUSED_LOCAL(instance_template);
684  v8::Local<v8::ObjectTemplate> prototype_template = interface_template->PrototypeTemplate();
685  ALLOW_UNUSED_LOCAL(prototype_template);
686
687  // Register IDL constants, attributes and operations.
688  {% for feature_name, constants_list in constants | selectattr('runtime_enabled_feature_name') | groupby('runtime_enabled_feature_name') %}
689  {% filter runtime_enabled(feature_name) %}
690  static constexpr V8DOMConfiguration::ConstantConfiguration kConfigurations[] = {
691      {% for constant in constants_list %}
692      {{constant_configuration(constant) | trim | indent(6)}},
693      {% endfor %}
694  };
695  V8DOMConfiguration::InstallConstants(
696      isolate, interface_template, prototype_template,
697      kConfigurations, base::size(kConfigurations));
698  {% endfilter %}
699  {% endfor %}
700
701  {% for feature_name, attribute_list in runtime_enabled_attributes | selectattr('is_data_type_property') | groupby('runtime_enabled_feature_name') %}
702  {% filter runtime_enabled(feature_name) %}
703  {{install_interface_objects(attribute_list | sort, 'instance_template', 'prototype_template') | trim | indent(2)}}
704  {% endfilter %}
705  {% endfor %}
706
707  {% for feature_name, attribute_list in runtime_enabled_attributes | selectattr('is_data_type_property', 'equalto', False) | groupby('runtime_enabled_feature_name') %}
708  {% filter runtime_enabled(feature_name) %}
709  {{install_attributes(attribute_list | sort, 'instance_template', 'prototype_template', 'interface_template') | trim | indent(2)}}
710  {% endfilter %}
711  {% endfor %}
712
713  {% if iterator_method and iterator_method.runtime_enabled_feature_name %}
714  {% filter exposed(iterator_method.exposed_test) %}
715  {% filter runtime_enabled(iterator_method.runtime_enabled_feature_name) %}
716  {% set symbol_alias = '"%s"' % iterator_method_alias
717                        if iterator_method_alias else 'nullptr' %}
718  // Iterator (@@iterator)
719  static constexpr V8DOMConfiguration::SymbolKeyedMethodConfiguration
720  kSymbolKeyedIteratorConfiguration = {
721      v8::Symbol::GetIterator,
722      {{symbol_alias}},
723      {{v8_class_or_partial}}::IteratorMethodCallback,
724      0,
725      v8::DontEnum,
726      V8DOMConfiguration::kOnPrototype,
727      V8DOMConfiguration::kCheckHolder,
728      V8DOMConfiguration::kDoNotCheckAccess,
729      V8DOMConfiguration::kHasSideEffect
730  };
731  V8DOMConfiguration::InstallMethod(
732      isolate, world, prototype_template, signature,
733      kSymbolKeyedIteratorConfiguration);
734  {% endfilter %}
735  {% endfilter %}
736  {% endif %}
737
738  // Custom signature
739  {% for method in methods | custom_registration(is_partial) %}
740  {% filter exposed(method.overloads.exposed_test_all
741                    if method.overloads else method.exposed_test) %}
742  {% set feature_name = method.overloads.runtime_enabled_all
743        if method.overloads else method.runtime_enabled_feature_name %}
744  {% if feature_name %}
745  {% filter runtime_enabled(feature_name) %}
746  {% if method.is_cross_origin %}
747  {{install_origin_safe_method(method, 'instance_template', 'prototype_template') | trim | indent(2)}}
748  {% else %}
749  {{install_custom_signature(method, 'instance_template', 'prototype_template', 'interface_template', 'signature') | trim | indent(2)}}
750  {% endif %}
751  {% endfilter %}
752  {% endif %}
753  {% endfilter %}
754  {% endfor %}
755}
756
757{% endif %}{# not is_array_buffer_or_view #}
758{% endblock %}
759{##############################################################################}
760{% block install_runtime_enabled %}
761{% if needs_runtime_enabled_installer %}
762{% from 'attributes.cc.tmpl' import accessor_configuration,
763        attribute_configuration, install_attributes, install_interface_objects,
764        with context %}
765{% from 'methods.cc.tmpl' import install_custom_signature with context %}
766{% if not is_partial %}
767void {{v8_class}}::InstallRuntimeEnabledFeatures(
768    v8::Isolate* isolate,
769    const DOMWrapperWorld& world,
770    v8::Local<v8::Object> instance,
771    v8::Local<v8::Object> prototype,
772    v8::Local<v8::Function> interface) {
773  {% if runtime_enabled_feature_name %}
774#error "We don't expect a runtime enabled interface {{v8_class_or_partial}} to have InstallRuntimeEnabledFeatures()."
775  {% endif %}
776
777  InstallRuntimeEnabledFeaturesImpl(isolate, world, instance, prototype, interface);
778  {% if has_partial_interface %}
779
780  // Call partial interface's installer.
781  install_runtime_enabled_features_function_(isolate, world, instance, prototype, interface);
782  {% endif %}
783}
784{% endif %}{# not is_partial #}
785
786void {{v8_class_or_partial}}::InstallRuntimeEnabledFeaturesImpl(
787    v8::Isolate* isolate,
788    const DOMWrapperWorld& world,
789    v8::Local<v8::Object> instance,
790    v8::Local<v8::Object> prototype,
791    v8::Local<v8::Function> interface) {
792  {% if runtime_enabled_feature_name %}
793#error "We don't expect a runtime enabled interface {{v8_class_or_partial}} to have InstallRuntimeEnabledFeatures()."
794  {% endif %}
795
796  v8::Local<v8::FunctionTemplate> interface_template = {{v8_class}}::GetWrapperTypeInfo()->DomTemplate(isolate, world);
797  v8::Local<v8::Signature> signature = v8::Signature::New(isolate, interface_template);
798  ALLOW_UNUSED_LOCAL(signature);
799
800  {# TODO(peria): Generate code to install constants. It depends on runtime_enabled_feaure of this interface. #}
801
802  {% for feature_name, attrs in runtime_enabled_attributes | selectattr('is_data_type_property') | groupby('runtime_enabled_feature_name') %}
803  {% filter runtime_enabled(feature_name) %}
804  {{install_interface_objects(attrs | sort, 'instance', 'prototype')}}
805  {% endfilter %}
806  {% endfor %}
807
808  {% for feature_name, attrs in runtime_enabled_attributes | selectattr('is_data_type_property', 'equalto', False) | groupby('runtime_enabled_feature_name') %}
809  {% filter runtime_enabled(feature_name) %}
810  {{install_attributes(attrs | sort, 'instance', 'prototype', 'interface') | trim | indent(2)}}
811  {% endfilter %}
812  {% endfor %}
813
814  {% if iterator_method and iterator_method.runtime_enabled_feature_name %}
815#error "{{v8_class_or_partial}} should not have runtime enabled iterator (@@iterator)."
816  {% endif %}
817
818  {% if methods | custom_registration(is_partial) %}
819  {% for method in methods | custom_registration(is_partial) %}
820  {% filter exposed(method.overloads.exposed_test_all
821                    if method.overloads else method.exposed_test) %}
822  {% set feature_name = (method.overloads.runtime_enabled_all
823                         if method.overloads else method.runtime_enabled_feature_name) %}
824  {% if feature_name %}
825  {% filter runtime_enabled(feature_name) %}
826  {% if method.is_cross_origin %}
827#error "{{v8_class_or_partial}} should not have runtime enabled and cross origin methods."
828  {% else %}
829  {{install_custom_signature(method, 'instance', 'prototype', 'interface', 'signature') | trim | indent(2)}}
830  {% endif %}
831  {% endfilter %}
832  {% endif %}
833  {% endfilter %}
834  {% endfor %}
835  {% endif %}
836}
837
838{% endif %}{# needs_runtime_enabled_installer #}
839{% endblock %}
840{##############################################################################}
841{% block origin_trials %}
842{% from 'attributes.cc.tmpl' import accessor_configuration,
843        attribute_configuration, install_attributes, install_interface_objects,
844        with context %}
845{% from 'constants.cc.tmpl' import constant_configuration with context %}
846{% from 'methods.cc.tmpl' import method_configuration with context %}
847{% for feature in optional_features %}
848void {{v8_class_or_partial}}::Install{{feature.name}}(
849    v8::Isolate* isolate,
850    const DOMWrapperWorld& world,
851    v8::Local<v8::Object> instance,
852    v8::Local<v8::Object> prototype,
853    v8::Local<v8::Function> interface) {
854  {% if feature.attributes or feature.methods %}
855  v8::Local<v8::FunctionTemplate> interface_template =
856      {{v8_class}}::GetWrapperTypeInfo()->DomTemplate(isolate, world);
857  v8::Local<v8::Signature> signature = v8::Signature::New(isolate, interface_template);
858  ALLOW_UNUSED_LOCAL(signature);
859  {% endif %}
860  {% if feature.needs_context %}
861  ExecutionContext* execution_context = ToExecutionContext(isolate->GetCurrentContext());
862  {% endif %}{# needs context #}
863  {% if feature.needs_secure_context %}
864  bool is_secure_context = (execution_context && execution_context->IsSecureContext());
865  {% endif %}{# needs secure context #}
866  {# Origin-Trial-enabled attributes #}
867  {% for secure_context_test, attribute_list in feature.attributes | selectattr('is_data_type_property') | groupby('secure_context_test') %}
868  {% filter secure_context(secure_context_test) %}
869  {{install_interface_objects(attribute_list, 'instance', 'prototype') | trim | indent(2)}}
870  {% endfilter %}
871  {% endfor %}
872  {% for secure_context_test, attribute_list in feature.attributes | rejectattr('is_data_type_property') | groupby('secure_context_test') %}
873  {% filter secure_context(secure_context_test) %}
874  {{install_attributes(attribute_list, 'instance', 'prototype', 'interface') | trim | indent(2)}}
875  {% endfilter %}{# secure_context #}
876  {% endfor %}
877  {# Origin-Trial-enabled constants #}
878  {% for constant in feature.constants %}
879  {% set constant_name = constant.camel_case_name %}
880  static constexpr V8DOMConfiguration::ConstantConfiguration
881  k{{constant_name}}Configuration = {{constant_configuration(constant)}};
882  V8DOMConfiguration::InstallConstant(
883      isolate, interface, prototype, k{{constant_name}}Configuration);
884  {% endfor %}
885  {# Origin-Trial-enabled methods (no overloads) #}
886  {% for method in feature.methods %}
887  {% filter exposed(method.exposed_test) %}
888  {% filter secure_context(method.secure_context_test) %}
889  static constexpr V8DOMConfiguration::MethodConfiguration
890  k{{method.camel_case_name}}Configurations[] = {
891      {{method_configuration(method) | trim | indent(6)}}
892  };
893  for (const auto& config : k{{method.camel_case_name}}Configurations) {
894    V8DOMConfiguration::InstallMethod(
895        isolate, world, instance, prototype,
896        interface, signature, config);
897  }
898  {% endfilter %}{# secure_context #}
899  {% endfilter %}{# exposed_test #}
900  {% endfor %}
901}
902
903void {{v8_class_or_partial}}::Install{{feature.name}}(
904    ScriptState* script_state, v8::Local<v8::Object> instance) {
905  V8PerContextData* per_context_data = script_state->PerContextData();
906  v8::Local<v8::Object> prototype = per_context_data->PrototypeForType(
907      {{v8_class}}::GetWrapperTypeInfo());
908  v8::Local<v8::Function> interface = per_context_data->ConstructorForType(
909      {{v8_class}}::GetWrapperTypeInfo());
910  ALLOW_UNUSED_LOCAL(interface);
911  Install{{feature.name}}(script_state->GetIsolate(), script_state->World(), instance, prototype, interface);
912}
913{% if not feature.needs_instance %}
914
915void {{v8_class_or_partial}}::Install{{feature.name}}(ScriptState* script_state) {
916  Install{{feature.name}}(script_state, v8::Local<v8::Object>());
917}
918{% endif %}
919
920{% endfor %}{# feature #}
921{% endblock %}
922{##############################################################################}
923{% block get_dom_template %}{% endblock %}
924{% block get_dom_template_for_named_properties_object %}{% endblock %}
925{% block has_instance %}{% endblock %}
926{% block to_impl %}{% endblock %}
927{% block to_impl_with_type_check %}{% endblock %}
928{##############################################################################}
929{% block install_conditional_features %}
930{% from 'attributes.cc.tmpl' import install_conditional_attributes,
931      install_conditional_interface_objects with context %}
932{% from 'methods.cc.tmpl' import install_conditional_methods with context %}
933{% if install_conditional_features_func %}
934void {{v8_class_or_partial}}::InstallConditionalFeatures(
935    v8::Local<v8::Context> context,
936    const DOMWrapperWorld& world,
937    v8::Local<v8::Object> instance_object,
938    v8::Local<v8::Object> prototype_object,
939    v8::Local<v8::Function> interface_object,
940    v8::Local<v8::FunctionTemplate> interface_template) {
941  CHECK(!interface_template.IsEmpty());
942  DCHECK((!prototype_object.IsEmpty() && !interface_object.IsEmpty()) ||
943         !instance_object.IsEmpty());
944  {% if is_partial %}
945  {{v8_class}}::InstallConditionalFeatures(
946      context, world, instance_object, prototype_object, interface_object, interface_template);
947  {% endif %}
948
949  v8::Isolate* isolate = context->GetIsolate();
950
951  {% if unscopables %}
952  if (!prototype_object.IsEmpty()) {
953    v8::Local<v8::Name> unscopables_symbol(v8::Symbol::GetUnscopables(isolate));
954    v8::Local<v8::Object> unscopables;
955    bool has_unscopables;
956    if (prototype_object->HasOwnProperty(context, unscopables_symbol)
957        .To(&has_unscopables) && has_unscopables) {
958      unscopables = prototype_object->Get(context, unscopables_symbol)
959                    .ToLocalChecked().As<v8::Object>();
960    } else {
961      // Web IDL 3.6.3. Interface prototype object
962      // https://heycam.github.io/webidl/#create-an-interface-prototype-object
963      // step 8.1. Let unscopableObject be the result of performing
964      //   ! ObjectCreate(null).
965      unscopables = v8::Object::New(isolate);
966      unscopables->SetPrototype(context, v8::Null(isolate)).ToChecked();
967    }
968    {% for name, runtime_enabled_feature_name in unscopables %}
969    {% filter runtime_enabled(runtime_enabled_feature_name) %}
970    unscopables->CreateDataProperty(
971        context, V8AtomicString(isolate, "{{name}}"), v8::True(isolate))
972        .FromJust();
973    {% endfilter %}
974    {% endfor %}
975    prototype_object->CreateDataProperty(
976        context, unscopables_symbol, unscopables).FromJust();
977  }
978  {% endif %}{# unscopables #}
979
980  {% if conditional_attributes or conditional_methods %}
981  v8::Local<v8::Signature> signature = v8::Signature::New(isolate, interface_template);
982  {% endif %}
983  {% if conditional_attributes or conditional_methods or conditional_interface_objects %}
984  ExecutionContext* execution_context = ToExecutionContext(context);
985  DCHECK(execution_context);
986  {% if has_conditional_secure_attributes or has_conditional_secure_methods %}
987  bool is_secure_context = (execution_context && execution_context->IsSecureContext());
988  {% endif %}
989
990  {% set attributes_on_instance = conditional_attributes | selectattr('on_instance') | list %}
991  {% set methods_on_instance = conditional_methods | selectattr('on_instance') | list %}
992  {% if attributes_on_instance or conditional_interface_objects or methods_on_instance %}
993  if (!instance_object.IsEmpty()) {
994    {{install_conditional_attributes(attributes_on_instance) | trim | indent(4)}}
995    {{install_conditional_interface_objects(conditional_interface_objects) | trim | indent(4)}}
996    {{install_conditional_methods(methods_on_instance) | trim | indent(4)}}
997  }
998  {% endif %}
999
1000  {% set attributes_on_prototype = conditional_attributes | selectattr('on_prototype') | list %}
1001  {% set attributes_on_interface = conditional_attributes | selectattr('on_interface') | list %}
1002  {% set methods_on_prototype = conditional_methods | selectattr('on_prototype') | list %}
1003  {% set methods_on_interface = conditional_methods | selectattr('on_interface') | list %}
1004  {% if attributes_on_prototype or attributes_on_interface or methods_on_prototype or methods_on_interface %}
1005  if (!prototype_object.IsEmpty() || !interface_object.IsEmpty()) {
1006    {{install_conditional_attributes(attributes_on_prototype + attributes_on_interface) | trim | indent(4)}}
1007    {{install_conditional_methods(methods_on_prototype + methods_on_interface) | trim | indent(4)}}
1008  }
1009  {% endif %}
1010  {% endif %}{# conditional_attributes or conditional_methods #}
1011}
1012{% endif %}
1013
1014{% endblock %}{# install_conditional_features #}
1015{##############################################################################}
1016{% block partial_interface %}{% endblock %}
1017}  // namespace blink
1018
1019{% endfilter %}{# format_blink_cpp_source_code #}
1020