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